home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fslcl / fslclLookup.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  83KB  |  2,516 lines

  1. /* 
  2.  * fslclLookup.c --
  3.  *
  4.  *    The routines in the module manage the directory structure.
  5.  *    The top level loop is in FslclLookup, and it is the workhorse
  6.  *    of the Local Domain that is called by procedures like FslclOpen.
  7.  *    Files and directories are also created, deleted, and renamed
  8.  *    directly (or indirectly) through FslclLookup.
  9.  *
  10.  *    Support for heterogenous systems is done here by expanding "$MACHINE"
  11.  *    in pathnames to a string like "sun3" or "spur".
  12.  *
  13.  * Copyright 1987 Regents of the University of California
  14.  * All rights reserved.
  15.  * Permission to use, copy, modify, and distribute this
  16.  * software and its documentation for any purpose and without
  17.  * fee is hereby granted, provided that the above copyright
  18.  * notice appear in all copies.  The University of California
  19.  * makes no representations about the suitability of this
  20.  * software for any purpose.  It is provided "as is" without
  21.  * express or implied warranty.
  22.  */
  23.  
  24. #ifndef lint
  25. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fslcl/fslclLookup.c,v 9.27 92/08/10 17:28:30 mgbaker Exp $ SPRITE (Berkeley)";
  26. #endif not lint
  27.  
  28.  
  29. #include <sprite.h>
  30. #include <fs.h>
  31. #include <fsconsist.h>
  32. #include <fsutil.h>
  33. #include <fsNameOps.h>
  34. #include <fsprefix.h>
  35. #include <fsdm.h>
  36. #include <fslclInt.h>
  37. #include <fslcl.h>
  38. #include <fslclNameHash.h>
  39. #include <fscache.h>
  40. #include <fsStat.h>
  41. #include <net.h>
  42. #include <vm.h>
  43. #include <string.h>
  44. #include <proc.h>
  45. #include <dbg.h>
  46. #include <fsrecov.h>
  47. #include <rpc.h>
  48. #include <recov.h>
  49.  
  50. int fsCompacts;        /* The number of times a directory block was so
  51.              * fragmented that we could have compacted it to
  52.              * make room for a new entry in the directory */
  53. /*
  54.  * A cache of recently seen pathname components is kept in a hash table.
  55.  * The hash table gets initialized in Fsdm_AttachDisk after the first disk
  56.  * gets attached.
  57.  * The name caching can be disabled by setting the fslclNameCaching flag to FALSE.
  58.  */
  59.  
  60. FslclHashTable fslclNameTable;
  61. FslclHashTable *fslclNameTablePtr = (FslclHashTable *)NIL;
  62. Boolean fslclNameCaching = TRUE;
  63. int fslclNameHashSize = FSLCL_NAME_HASH_SIZE;
  64.  
  65. /*
  66.  * Forward Declarations.
  67.  */
  68.  
  69. static ReturnStatus FindComponent _ARGS_((Fsio_FileIOHandle *parentHandlePtr, 
  70.         char *component, int compLen, Boolean isDotDot, 
  71.         Fsio_FileIOHandle **curHandlePtrPtr, int *dirOffsetPtr));
  72. static ReturnStatus InsertComponent _ARGS_((Fsio_FileIOHandle *curHandlePtr, 
  73.         char *component, int compLen, int fileNumber,
  74.         int *dirOffsetPtr));
  75. static ReturnStatus DeleteComponent _ARGS_((Fsio_FileIOHandle *parentHandlePtr,
  76.         char *component, int compLen, int *dirOffsetPtr));
  77. static ReturnStatus ExpandLink _ARGS_((Fsio_FileIOHandle *curHandlePtr, 
  78.         char *curCharPtr, int offset, char nameBuffer[]));
  79. static ReturnStatus GetHandle _ARGS_((int fileNumber, 
  80.         Fsdm_FileDescriptor *newDescPtr, 
  81.         Fsio_FileIOHandle *curHandlePtr, char *name, 
  82.         Fsio_FileIOHandle **newHandlePtrPtr));
  83. static ReturnStatus CreateFile _ARGS_((Fsdm_Domain *domainPtr, 
  84.         Fsio_FileIOHandle *parentHandlePtr, char *component, 
  85.         int compLen, int fileNumber, int type, int permissions, 
  86.         Fs_UserIDs *idPtr, Fsio_FileIOHandle **curHandlePtrPtr, 
  87.         int *dirOffsetPtr));
  88. static ReturnStatus WriteNewDirectory _ARGS_((Fsio_FileIOHandle *curHandlePtr,
  89.         Fsio_FileIOHandle *parentHandlePtr));
  90. static ReturnStatus LinkFile _ARGS_((Fsio_FileIOHandle *parentHandlePtr,
  91.         char *component, int compLen, int fileNumber, int logOp, 
  92.         Fsio_FileIOHandle **curHandlePtrPtr, int clientID));
  93. static ReturnStatus OkToMoveDirectory _ARGS_((
  94.         Fsio_FileIOHandle *newParentHandlePtr, 
  95.         Fsio_FileIOHandle *curHandlePtr));
  96. static ReturnStatus MoveDirectory _ARGS_((Time *modTimePtr, 
  97.         Fsio_FileIOHandle *newParentHandlePtr, 
  98.         Fsio_FileIOHandle *curHandlePtr));
  99. static ReturnStatus GetParentNumber _ARGS_((Fsio_FileIOHandle *curHandlePtr,
  100.         int *parentNumberPtr));
  101. static ReturnStatus SetParentNumber _ARGS_((Fsio_FileIOHandle *curHandlePtr, 
  102.         int newParentNumber));
  103. static ReturnStatus DeleteFileName _ARGS_((Fsio_FileIOHandle *parentHandlePtr,
  104.         Fsio_FileIOHandle *curHandlePtr, char *component, int compLen,
  105.         int forRename, Fs_UserIDs *idPtr, int logOp, int clientID));
  106. static void    CloseDeletedFile _ARGS_((Fsio_FileIOHandle **parentHandlePtrPtr,
  107.                     Fsio_FileIOHandle **curHandlePtrPtr));
  108. static Boolean DirectoryEmpty _ARGS_((Fsio_FileIOHandle *handlePtr));
  109. static ReturnStatus CheckPermissions _ARGS_((Fsio_FileIOHandle *handlePtr, 
  110.         int useFlags, Fs_UserIDs *idPtr, int type));
  111. static ReturnStatus CacheDirBlockWrite _ARGS_((Fsio_FileIOHandle *handlePtr, 
  112.         Fscache_Block *blockPtr, int blockNum, int length));
  113.  
  114.  
  115. /*
  116.  *----------------------------------------------------------------------
  117.  *
  118.  * FslclLookup --
  119.  *
  120.  *    The guts of local file name lookup.  This does a recursive
  121.  *    directory lookup of a file pathname.  The success of the lookup
  122.  *    depends on useFlags and the type.  The process needs to
  123.  *    have read permission along the path, and other permissions on
  124.  *    the target file itself according to useFlags. The type of the
  125.  *    target file has to agree with the type parameter.
  126.  *
  127.  *    The major and minor fields of the Fs_FileID for local files correspond
  128.  *    to the domain and fileNumber, respectively, of a file.  The domain
  129.  *    is an index into the set of active domains (disks), and the fileNumber
  130.  *    is an index into the array of file descriptors on disk.
  131.  *
  132.  * Results:
  133.  *    If SUCCESS is returned then *handlePtrPtr contains a valid file
  134.  *    handle.  This handle should be released with FsLocalClose.
  135.  *    If FS_LOOKUP_REDIRECT is returned then **newNameInfoPtrPtr contains
  136.  *    the new file name that the client takes back to its prefix table.
  137.  *
  138.  * Side effects:
  139.  *    After a successful lookup the returned handle is locked and has
  140.  *    another reference to it.  Also, the domain in which the file was
  141.  *    found has an extra reference that needs to be released with
  142.  *    Fsdm_DomainRelease as soon as our caller is finished with the handle.
  143.  *
  144.  *----------------------------------------------------------------------
  145.  */
  146. ReturnStatus
  147. FslclLookup(prefixHdrPtr, relativeName, rootIDPtr, useFlags, type, clientID,
  148.         idPtr, permissions, fileNumber, handlePtrPtr, newNameInfoPtrPtr)
  149.     Fs_HandleHeader *prefixHdrPtr;    /* Handle from the prefix table or
  150.                      * the current working directory */
  151.     char *relativeName;            /* Name to lookup relative to the
  152.                      * file indicated by prefixHandlePtr */
  153.     Fs_FileID *rootIDPtr;        /* File ID of the root of the domain */
  154.     int useFlags;            /* FS_READ|FS_WRITE|FS_EXECUTE,
  155.                      * FS_CREATE|FS_EXCLUSIVE, FS_OWNER,
  156.                      * FS_LINK, FS_FOLLOW (links) */
  157.     int type;                /* File type which to succeed on.  If
  158.                      * this is FS_FILE, then any type will
  159.                      * work. */
  160.     int clientID;            /* Host ID of the client doing the open.
  161.                      * Require to properly expand $MACHINE
  162.                      * in pathnames */
  163.     Fs_UserIDs *idPtr;            /* User and group IDs */
  164.     int permissions;            /* Permission bits to use on a newly
  165.                      * created file. */
  166.     int fileNumber;            /* File number to link to if FS_LINK
  167.                      * useFlag is present */
  168.     Fsio_FileIOHandle **handlePtrPtr;    /* Result, the handle for the file.
  169.                      * This is returned locked.  Also,
  170.                      * its domain has a reference which
  171.                      * needs to be released. */
  172.     Fs_RedirectInfo **newNameInfoPtrPtr;    /* Redirect Result, the pathname left
  173.                      * after it leaves our domain */
  174. {
  175.     register char     *curCharPtr;    /* Pointer into the path name */
  176.     Fsio_FileIOHandle *parentHandlePtr; /* Handle for parent dir. */
  177.     register char    *compPtr;    /* Pointer into component. */
  178.     register ReturnStatus status = SUCCESS;
  179.     register int     compLen = 0;    /* The length of component */
  180.     Fsio_FileIOHandle    *curHandlePtr;    /* Handle for the current spot in
  181.                      * the directory structure */
  182.     Fsdm_Domain *domainPtr;        /* Domain of the lookup */
  183.     char component[FS_MAX_NAME_LENGTH]; /* One component of the path name */
  184.     char *newNameBuffer;        /* Extra buffer used after a symbolic
  185.                      * link has been expanded */
  186.     int numLinks = 0;            /* The number of links that have been
  187.                      * expanded. Used to check against
  188.                      * loops. */
  189.     int    logOp;                /* Dir log operation. */
  190.     int dirFileNumber;            /* File number od directory being 
  191.                      * operated on. */
  192.     int    dirOffset;            /* Offset of directory entry in the
  193.                      * directory being operated on. */
  194.     ClientData    logClientData;        /* Client data for directory change
  195.                      * logging. */
  196.     ClientData    recovLogClientData = (ClientData) 0;
  197.                     /* Client data for directory change
  198.                      * logging in the recovery system. */
  199.     /*
  200.      * Get a handle on the domain of the file.  This is needed for disk I/O.
  201.      * Remember that the <major> field of the fileID is a domain number.
  202.      */
  203.     domainPtr = Fsdm_DomainFetch(prefixHdrPtr->fileID.major, FALSE);
  204.     if (domainPtr == (Fsdm_Domain *)NIL) {
  205.     return(FS_DOMAIN_UNAVAILABLE);
  206.     }
  207.  
  208.     if (prefixHdrPtr->fileID.type != FSIO_LCL_FILE_STREAM) {
  209.     printf("FslclLookup, bad prefix handle type <%d> for {%s}%s\n",
  210.         prefixHdrPtr->fileID.type,
  211.         Fsutil_HandleName(prefixHdrPtr), relativeName);
  212.     return(FS_DOMAIN_UNAVAILABLE);
  213.     }
  214.     /*
  215.      * Duplicate the prefixHandle into the handle for the current point
  216.      * in the directory.  This locks and ups the reference count on the handle.
  217.      */
  218.     curCharPtr = relativeName;
  219.     curHandlePtr = Fsutil_HandleDupType(Fsio_FileIOHandle, prefixHdrPtr);
  220.     parentHandlePtr = (Fsio_FileIOHandle *)NIL;
  221.     newNameBuffer = (char *)NIL;
  222.     /*
  223.      * Loop through the pathname expanding links and checking permissions.
  224.      * Creations and deletions are handled after this loop.
  225.      */
  226.     fs_Stats.lookup.number++;
  227.     while (*curCharPtr != '\0' && status == SUCCESS) {
  228.     status = CheckPermissions(curHandlePtr, FS_READ, idPtr, FS_DIRECTORY);
  229.     if (status != SUCCESS) {
  230.         break;
  231.     }
  232.     /*
  233.      * Get the next component.  We make a special check here
  234.      * for "$MACHINE" embedded in the pathname.  This gets expanded
  235.      * to a machine type string, i.e. "sun3" or "spur", sort of like
  236.      * a symbolic link.  The value is dependent on the ID of the client
  237.      * doing the open.  For the local host we use a compiled in string so
  238.      * we can bootstrap ok, and for other clients we get the machine
  239.      * type string from the net module.  (why net?  why not...
  240.      * Net_InstallRoute installs a host's name and machine type.)
  241.      */
  242. #define SPECIAL        "$MACHINE"
  243. #define SPECIAL_LEN    8
  244.     compPtr = component;
  245.     while (*curCharPtr != '/' && *curCharPtr != '\0') {
  246.         if (*curCharPtr == '$' &&
  247.         (strncmp(curCharPtr, SPECIAL, SPECIAL_LEN) == 0)) {
  248.         char machTypeBuffer[32];
  249.         char *machType;
  250.  
  251.         fs_Stats.lookup.numSpecial++;
  252.         if (clientID == rpc_SpriteID) {
  253.             /*
  254.              * Can't count on the net stuff being setup for ourselves
  255.              * as that is done via a user program way after bootting.
  256.              * Instead, use a compiled in string.  This is important
  257.              * when opening "/initSprite", which is a link to 
  258.              * "/initSprite.$MACHINE", when running on the root server.
  259.              */
  260.             machType = mach_MachineType;
  261.         } else {
  262.             Net_SpriteIDToMachType(clientID, 32, machTypeBuffer);
  263.             if (*machTypeBuffer == '\0') {
  264.             printf(
  265.              "FslclLookup, no machine type for client %d\n",
  266.                 clientID);
  267.             machType = "unknown";
  268.             } else {
  269.             machType = machTypeBuffer;
  270.             }
  271.         }
  272.         while (*machType != '\0') {
  273.             *compPtr++ = *machType++;
  274.             if (compPtr - component >= FS_MAX_NAME_LENGTH) {
  275.             status = FS_INVALID_ARG;
  276.             goto endScan;
  277.             }
  278.         }
  279.         curCharPtr += SPECIAL_LEN;
  280. #undef SPECIAL
  281. #undef SPECIAL_LEN
  282.         } else {
  283.         *compPtr++ = *curCharPtr++;
  284.         }
  285.         if (compPtr - component >= FS_MAX_NAME_LENGTH) {
  286.         status = FS_INVALID_ARG;
  287.         goto endScan;
  288.         }
  289.     }
  290.     fs_Stats.lookup.numComponents++;
  291.     *compPtr = '\0';
  292.     compLen = compPtr - component;
  293.     /*
  294.      * Skip intermediate and trailing slashes so that *curCharPtr
  295.      * is Null when 'component' has the last component of the name.
  296.      */
  297.     while (*curCharPtr == '/') {
  298.         curCharPtr++;
  299.     }
  300.     /*
  301.      * There are three cases for what the next component is:
  302.      * a sub-directory (or file), dot, and dot-dot.
  303.      */
  304.     if ((compLen == 2) && component[0] == '.' && component[1] == '.') {
  305.         /* 
  306.          * Going to the parent directory ".."
  307.          */
  308.         if (curHandlePtr->hdr.fileID.minor == rootIDPtr->minor) {
  309.         /*
  310.          * We are falling off the top of the domain.  Make the
  311.          * remaining part of the filename, including "../",
  312.          * available to our caller so it can go back to the prefix
  313.          * table.  Setting the prefixLength to zero indicates
  314.          * there is no prefix information in this LOOKUP_REDIRECT
  315.          */
  316.         *newNameInfoPtrPtr = mnew(Fs_RedirectInfo);
  317.         (*newNameInfoPtrPtr)->prefixLength = 0;
  318.         (void)strcpy((*newNameInfoPtrPtr)->fileName, "../");
  319.         (void)strcat((*newNameInfoPtrPtr)->fileName, curCharPtr);
  320.         fs_Stats.lookup.parent++;
  321.         status = FS_LOOKUP_REDIRECT;
  322.         } else {
  323.         /*
  324.          * Advance curHandlePtr to the parent, "..".
  325.          * FindComponent will unlock its parentHandlePtr (the directory
  326.          * containing "..") after scanning it but before grabbing
  327.          * the handle for "..".  This prevents deadlock with another
  328.          * process descending the other way along the path.  
  329.          * We then nuke our own "parent" because it really isn't a
  330.          * parent anymore.
  331.          */
  332.         if (parentHandlePtr != (Fsio_FileIOHandle *)NIL) {
  333.             Fsutil_HandleRelease(parentHandlePtr, TRUE);
  334.         }
  335.         parentHandlePtr = curHandlePtr;
  336.         status = FindComponent(parentHandlePtr, component, compLen,
  337.                 TRUE, &curHandlePtr, &dirOffset);
  338.         /*
  339.          * Release the handle while being careful about its lock.
  340.          * The parent handle is normally aready unlocked by
  341.          * FindComponent, unless the directory is corrupted.
  342.          */
  343.         Fsutil_HandleRelease(parentHandlePtr, (status != SUCCESS));
  344.         parentHandlePtr = (Fsio_FileIOHandle *)NIL;
  345.         }
  346.     } else if ((compLen == 1) && component[0] == '.') {
  347.         /*
  348.          * Just hang tight with . (dot) because we already
  349.          * have a locked handle for it.
  350.          */
  351.     } else {
  352.         /*
  353.          * Advance to the next component and keep the handle on
  354.          * the parent locked so we can do deletes and creates.
  355.          */
  356.         if (parentHandlePtr != (Fsio_FileIOHandle *)NIL) {
  357.         Fsutil_HandleRelease(parentHandlePtr, TRUE);
  358.         }
  359.         parentHandlePtr = curHandlePtr;
  360.         status = FindComponent(parentHandlePtr, component, compLen, FALSE,
  361.             &curHandlePtr, &dirOffset);
  362.     }
  363.     /*
  364.      * At this point we have a locked handle on the current point
  365.      * in the lookup, and perhaps have a locked handle on the parent.
  366.      * Links are expanded now so we know whether or not the
  367.      * lookup is completed.  On the last component, we only
  368.      * expand the link if the FS_FOLLOW flag is present.
  369.      */
  370.     if ((status == SUCCESS) &&
  371.         ((*curCharPtr != '\0') || (useFlags & FS_FOLLOW)) &&
  372.         ((curHandlePtr->descPtr->fileType == FS_SYMBOLIC_LINK ||
  373.         curHandlePtr->descPtr->fileType == FS_REMOTE_LINK))) {
  374.         numLinks++;
  375.         fs_Stats.lookup.symlinks++;
  376.         if (numLinks > FS_MAX_LINKS) {
  377.         status = FS_NAME_LOOP;
  378.         } else {
  379.         /*
  380.          * An extra buffer is used because the caller probably only
  381.          * has a buffer just big enough for the name.
  382.          */
  383.         int     offset;        /* Distance of existing name from
  384.                      * the start of its buffer */
  385.         if (newNameBuffer == (char *)NIL) {
  386.             offset = (int)curCharPtr - (int)relativeName;
  387.             newNameBuffer = (char *)malloc(FS_MAX_PATH_NAME_LENGTH);
  388.         } else {
  389.             offset = (int)curCharPtr - (int)newNameBuffer;
  390.         }
  391.         status = ExpandLink(curHandlePtr, curCharPtr, offset,
  392.                             newNameBuffer);
  393.         if (status == FS_FILE_NOT_FOUND) {
  394.             printf( "FslclLookup, empty link \"%s\"\n",
  395.                 relativeName);
  396.         }
  397.         curCharPtr = newNameBuffer;
  398.         }
  399.         if (status == SUCCESS) {
  400.         /*
  401.          * (Note: One could enforce permissions on links here.)
  402.          * If the link is back to the root we have to REDIRECT,
  403.          * otherwise retreat the current point in the lookup to
  404.          * the parent directory before continuing.
  405.          */
  406.         if (*curCharPtr == '/') {
  407.             *newNameInfoPtrPtr = mnew(Fs_RedirectInfo);
  408.             (void)strcpy((*newNameInfoPtrPtr)->fileName, curCharPtr);
  409.             status = FS_LOOKUP_REDIRECT;
  410.             /*
  411.              * Return the length of the prefix indicated by
  412.              * a remote link, zero means no prefix.
  413.              */
  414.             if (curHandlePtr->descPtr->fileType == FS_REMOTE_LINK) {
  415.             fs_Stats.lookup.remote++;
  416.             (*newNameInfoPtrPtr)->prefixLength = 
  417.                         curHandlePtr->descPtr->lastByte;
  418.             } else {
  419.             fs_Stats.lookup.redirect++;
  420.             (*newNameInfoPtrPtr)->prefixLength = 0;
  421.             }
  422.         } else if (parentHandlePtr != (Fsio_FileIOHandle *)NIL) {
  423.             Fsutil_HandleRelease(curHandlePtr, TRUE);
  424.             curHandlePtr = parentHandlePtr;
  425.             parentHandlePtr = (Fsio_FileIOHandle *)NIL;
  426.             status = SUCCESS;
  427.         } else {
  428.             panic( "No parent after link");
  429.             status = FS_INVALID_ARG;
  430.         }
  431.         }
  432.     }
  433.     }
  434. endScan:
  435.     if ((status == SUCCESS) ||
  436.     ((status == FS_FILE_NOT_FOUND) && (*curCharPtr == '\0'))) {
  437.     /*
  438.      * Done with the lookup.  Determine the type of the file once
  439.      * we have a handle for it if its type is not already set from the
  440.      * file descriptor. Process creates, links, and deletes.
  441.      */
  442.     switch(useFlags & (FS_CREATE|FS_DELETE|FS_LINK)) {
  443.         case 0:
  444.         if (status == SUCCESS) {
  445.             /*
  446.              * Normal lookup completion.
  447.              */
  448.             status = CheckPermissions(curHandlePtr, useFlags, idPtr,
  449.                         type);
  450.         }
  451.         break;
  452.         case FS_CREATE:
  453.         fs_Stats.lookup.forCreate++;
  454.         if (status == SUCCESS && (useFlags & FS_EXCLUSIVE)) {
  455.             /*
  456.              * FS_EXCLUSIVE and FS_CREATE means that the file
  457.              * cannot already exist.
  458.              */
  459.             status = FS_FILE_EXISTS;
  460.         } else if (status == FS_FILE_NOT_FOUND) {
  461.             /*
  462.              * 'component' is the last part of a pathname for a
  463.              * file we need to create and that doesn't exist.
  464.              * Check for write permission in the parent directory,
  465.              * choose a fileNumber for the new file, and then
  466.              * create the file itself.
  467.              */
  468.             int     newFileNumber;
  469.             int     nearbyFile;
  470.  
  471.             status = CheckPermissions(parentHandlePtr, FS_WRITE, idPtr,
  472.                             FS_DIRECTORY);
  473.             if (status == SUCCESS) {
  474.             int logOp;
  475.             dirFileNumber = parentHandlePtr->hdr.fileID.minor;
  476.             newFileNumber = -1;
  477.             dirOffset = -1;
  478.             if (type == FS_DIRECTORY) {
  479.                 logOp = FSDM_LOG_CREATE|FSDM_LOG_IS_DIRECTORY;
  480.                 nearbyFile = -1;
  481.             } else {
  482.                 logOp = FSDM_LOG_CREATE;
  483.                 nearbyFile = dirFileNumber;
  484.             }
  485.             logClientData = Fsdm_DirOpStart(logOp,
  486.                       parentHandlePtr, dirOffset,
  487.                       component, compLen,
  488.                       newFileNumber, type,
  489.                       (Fsdm_FileDescriptor *) NIL);
  490.             if (recov_Transparent && clientID != rpc_SpriteID) {
  491.                 recovLogClientData = Fsrecov_DirOpStart(logOp,
  492.                           parentHandlePtr, dirOffset,
  493.                           component, compLen,
  494.                           newFileNumber, type,
  495.                           (Fsdm_FileDescriptor *) NIL);
  496.             }
  497.             status = Fsdm_GetNewFileNumber(domainPtr, nearbyFile,
  498.                                  &newFileNumber);
  499.             if (status == SUCCESS) {
  500.                 status = CreateFile(domainPtr, parentHandlePtr,
  501.                      component, compLen, newFileNumber, type,
  502.                      permissions, idPtr, &curHandlePtr,
  503.                      &dirOffset);
  504.                 if (status != SUCCESS) {
  505.                 (void)Fsdm_FreeFileNumber(domainPtr,
  506.                         newFileNumber);
  507.                 } 
  508.             }
  509.             if (status == SUCCESS) { 
  510.                 Fsdm_DirOpEnd(logOp, 
  511.                     parentHandlePtr, dirOffset,
  512.                     component, compLen, newFileNumber, type,
  513.                     curHandlePtr->descPtr, logClientData, 
  514.                     status);
  515.                 if (recov_Transparent && clientID != rpc_SpriteID) {
  516.                 Fsrecov_DirOpEnd(logOp, 
  517.                     parentHandlePtr, dirOffset,
  518.                     component, compLen, newFileNumber, type,
  519.                     curHandlePtr->descPtr,
  520.                     recovLogClientData, status);
  521.                 }
  522.             } else {
  523.                 Fsdm_DirOpEnd(logOp, 
  524.                      parentHandlePtr, dirOffset,
  525.                      component, compLen, newFileNumber, type,
  526.                      (Fsdm_FileDescriptor *) NIL, 
  527.                      logClientData, status);
  528.                 if (recov_Transparent && clientID != rpc_SpriteID) {
  529.                 Fsrecov_DirOpEnd(logOp, 
  530.                      parentHandlePtr, dirOffset,
  531.                      component, compLen, newFileNumber,
  532.                      type, (Fsdm_FileDescriptor *) NIL, 
  533.                      recovLogClientData, status);
  534.                 }
  535.             }
  536.             }
  537.         } else {
  538.             /*
  539.              * If the file exists, it's like a normal lookup completion
  540.              * and we have to check permissions.
  541.              */
  542.             status = CheckPermissions(curHandlePtr, useFlags, idPtr,
  543.                         type);
  544.         }
  545.         if (status == SUCCESS) {
  546.             (void)Fsdm_FileDescStore(curHandlePtr, FALSE);
  547.         }
  548.         break;
  549.         case FS_LINK: {
  550.         Boolean         fileDeleted = FALSE;
  551.         Fsio_FileIOHandle    *deletedHandlePtr;
  552.         /*
  553.          * The presence of FS_LINK means that curHandlePtr references
  554.          * a file that is being linked to.  If the file already exists
  555.          * it is deleted first.  Then link is made with LinkFile.
  556.          */
  557.         if (useFlags & FS_RENAME) {
  558.             logOp = FSDM_LOG_RENAME_LINK;
  559.             fs_Stats.lookup.forRename++;
  560.         } else {
  561.             logOp = FSDM_LOG_LINK;
  562.             fs_Stats.lookup.forLink++;
  563.         }
  564.         dirFileNumber = parentHandlePtr->hdr.fileID.minor;
  565.         if (status == SUCCESS) {
  566.             /*
  567.              * Linking to an existing file.
  568.              * This can only be in preparation for a rename.
  569.              */
  570.             if ((useFlags & FS_RENAME) &&
  571.             (curHandlePtr->descPtr->fileType == type)) {
  572.  
  573.             /*
  574.              * Make sure the two files aren't actually the
  575.              * same.  If they are then just return SUCCESS,
  576.              * otherwise we would deadlock when we try to lock
  577.              * both file handles, unaware that they are the
  578.              * same handle.
  579.              */
  580.             if (fileNumber == curHandlePtr->hdr.fileID.minor) {
  581.                 break;
  582.             }
  583.             /*
  584.              * Try the delete, this fails on non-empty directories.
  585.              */
  586.             deletedHandlePtr = curHandlePtr;
  587.             status = DeleteFileName(parentHandlePtr,
  588.                   curHandlePtr, component, compLen, FALSE, idPtr,
  589.                   FSDM_LOG_RENAME_DELETE, clientID);
  590.             if (status == SUCCESS) {
  591.                 fileDeleted = TRUE;
  592.             }
  593.             } else {
  594.             /*
  595.              * Not ok to link to an existing file.
  596.              */
  597.             status = FS_FILE_EXISTS;
  598.             }
  599.         } else if (status == FS_FILE_NOT_FOUND) {
  600.             /*
  601.              * The file does not already exist.  Check write permission
  602.              * in the parent before making the link.
  603.              */
  604.             status = CheckPermissions(parentHandlePtr, FS_WRITE, idPtr,
  605.                             FS_DIRECTORY);
  606.         }
  607.         if (status == SUCCESS) {
  608.             status = LinkFile(parentHandlePtr,
  609.                 component, compLen, fileNumber, logOp,
  610.                 &curHandlePtr, clientID);
  611.             if (status == SUCCESS) {
  612.             (void)Fsdm_FileDescStore(curHandlePtr, FALSE);
  613.             }
  614.         }
  615.         if (fileDeleted) {
  616.             CloseDeletedFile(&parentHandlePtr, &deletedHandlePtr);
  617.         }
  618.         break;
  619.         }
  620.         case FS_DELETE:
  621.         fs_Stats.lookup.forDelete++;
  622.         if (status == SUCCESS) {
  623.             if ((curHandlePtr->descPtr->fileType != type) &&
  624.             (type != FS_FILE)) {
  625.             status = (type == FS_DIRECTORY) ? FS_NOT_DIRECTORY :
  626.                               FS_WRONG_TYPE;
  627.             } else {
  628.             logOp = (useFlags&FS_RENAME) ? FSDM_LOG_RENAME_UNLINK :
  629.                                FSDM_LOG_UNLINK;
  630.             status = DeleteFileName(parentHandlePtr, curHandlePtr,
  631.                 component, compLen,
  632.                 (int) (useFlags & FS_RENAME), idPtr, logOp,
  633.                 clientID);
  634.             if (status == SUCCESS) {
  635.                 CloseDeletedFile(&parentHandlePtr,
  636.                     &curHandlePtr);
  637.             }
  638.             }
  639.         }
  640.         break;
  641.     }
  642.     }
  643.  
  644.     /*
  645.      * Clean up state and return a fileHandle to our caller.
  646.      */
  647.     if (newNameBuffer != (char *)NIL) {
  648.     free(newNameBuffer);
  649.     }
  650.     if (parentHandlePtr != (Fsio_FileIOHandle *)NIL) {
  651.     Fsutil_HandleRelease(parentHandlePtr, TRUE);
  652.     }
  653.     if (curHandlePtr != (Fsio_FileIOHandle *)NIL) {
  654.     if (status != SUCCESS) {
  655.         Fsutil_HandleRelease(curHandlePtr, TRUE);
  656.         curHandlePtr = (Fsio_FileIOHandle *)NIL;
  657.     } 
  658.     }
  659.     if (handlePtrPtr != (Fsio_FileIOHandle **)NIL) {
  660.     /*
  661.      * Return a locked handle that has had its reference count bumped.
  662.      */
  663.     *handlePtrPtr = curHandlePtr;
  664.     } else if (curHandlePtr != (Fsio_FileIOHandle *)NIL) {
  665.     printf( "FslclLookup: caller didn't want handle\n");
  666.     Fsutil_HandleRelease(curHandlePtr, TRUE);
  667.     }
  668.     if ((status != SUCCESS) ||
  669.     (handlePtrPtr == (Fsio_FileIOHandle **)NIL)) {
  670.     Fsdm_DomainRelease(prefixHdrPtr->fileID.major);
  671.     }
  672.     if (status == FS_FILE_NOT_FOUND) {
  673.     fs_Stats.lookup.notFound++;
  674.     }
  675.     return(status);
  676. }
  677.  
  678.  
  679. /*
  680.  *----------------------------------------------------------------------
  681.  *
  682.  * FindComponent --
  683.  *
  684.  *    Look for a pathname component in a directory.  This returns a locked
  685.  *    file handle that has its reference count incremented.
  686.  *
  687.  * Results:
  688.  *    SUCCESS or FS_FILE_NOT_FOUND
  689.  *
  690.  * Side effects:
  691.  *    Disk I/O, installing and locking the handle.
  692.  *
  693.  *----------------------------------------------------------------------
  694.  */
  695. static ReturnStatus
  696. FindComponent(parentHandlePtr, component, compLen, isDotDot, curHandlePtrPtr,
  697.           dirOffsetPtr)
  698.     Fsio_FileIOHandle    *parentHandlePtr;    /* Locked handle of current 
  699.                          * directory */
  700.     register char     *component;        /* Name of path component to 
  701.                          * find */
  702.     register int     compLen;        /* The number of characters in 
  703.                          * component */
  704.     Boolean        isDotDot;        /* TRUE if component is "..".
  705.                          * In this case the handle for
  706.                          * the parent is returned
  707.                          * UNLOCKED. */
  708.     Fsio_FileIOHandle    **curHandlePtrPtr;    /* Return, locked handle */
  709.     int            *dirOffsetPtr;        /* OUT: Offset into directory
  710.                          * off component. */
  711. {
  712.     register Fslcl_DirEntry *dirEntryPtr;    /* Reference to directory entry */
  713.     register char    *s1;        /* Pointers into components used */
  714.     register char    *s2;        /*   for fast in-line string compare */
  715.     register int     blockOffset;    /* Offset within the directory */
  716.     ReturnStatus     status;
  717.     Fscache_Block    *cacheBlockPtr;    /* Cache block */
  718.     int         dirBlockNum;    /* Block number within directory */
  719.     int         length;        /* Length variable for read call */
  720.     FslclHashEntry        *entryPtr;    /* Name cache entry */
  721.     Fs_FileID        fileID;        /* Used when fetching handles */
  722.  
  723.     /*
  724.      * Check in system-wide name cache here before scanning
  725.      * the directory's data blocks.
  726.      */
  727.     entryPtr = FSLCL_HASH_LOOK_ONLY(fslclNameTablePtr, component, parentHandlePtr);
  728.     if (entryPtr != (FslclHashEntry *)NIL) {
  729.     if (entryPtr->hdrPtr->fileID.type != FSIO_LCL_FILE_STREAM) {
  730.         panic(
  731.               "FindComponent: got trashy handle from cache");
  732.     } else {
  733.         if (isDotDot) {
  734.         /*
  735.          * Unlock this directory before grabbing the handle for "..".
  736.          * This prevents deadlock with another lookup that is
  737.          * descending from our parent ("..") into this directory.
  738.          */
  739.         Fsutil_HandleUnlock(parentHandlePtr);
  740.         }
  741.         *curHandlePtrPtr = Fsutil_HandleDupType(Fsio_FileIOHandle,
  742.                         entryPtr->hdrPtr);
  743.         return(SUCCESS);
  744.     }
  745.     }
  746.  
  747.     dirBlockNum = 0;
  748.     do {
  749.     status = Fscache_BlockRead(&parentHandlePtr->cacheInfo, dirBlockNum,
  750.             &cacheBlockPtr, &length, FSCACHE_DIR_BLOCK, FALSE);
  751.     if (status != SUCCESS || length == 0) {
  752.         *curHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  753.         return(FS_FILE_NOT_FOUND);
  754.     }
  755.     dirEntryPtr = (Fslcl_DirEntry *)cacheBlockPtr->blockAddr;
  756.     blockOffset = 0;
  757.     while (blockOffset < length) {
  758.         if (dirEntryPtr->recordLength <= 0) {
  759.         printf("Corrupted directory?");
  760.         printf(" File ID <%d, %d, %d>",
  761.                  parentHandlePtr->hdr.fileID.serverID,
  762.                  parentHandlePtr->hdr.fileID.major,
  763.                  parentHandlePtr->hdr.fileID.minor);
  764.         printf(" dirBlockNum <%d>, blockOffset <%d>",
  765.                  dirBlockNum, blockOffset);
  766.         printf("\n");
  767.         Fscache_UnlockBlock(cacheBlockPtr, (time_t) 0,
  768.                             -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  769.         *curHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  770.         return(FS_FILE_NOT_FOUND);
  771.         }
  772.  
  773.         if (dirEntryPtr->fileNumber != 0) {
  774.         /*
  775.          * A valid directory record.  If component and the directory
  776.          * entry are the same length then compare them for a match.
  777.          * This String Compare is in-lined for efficiency.
  778.          */
  779.         if ((dirEntryPtr->nameLength == compLen)) {
  780.             s1 = component;
  781.             s2 = dirEntryPtr->fileName;
  782.             do {
  783.             if (*s1 == '\0') {
  784.                 /*
  785.                  * The strings are the same length so hitting
  786.                  * the end of component indicates a match.
  787.                  */
  788.                 if (isDotDot) {
  789.                 /*
  790.                  * Unlock this directory before grabbing the
  791.                  * handle for "..".  This prevents deadlock
  792.                  * with another lookup that is descending
  793.                  * from our parent ("..") into this directory.
  794.                  */
  795.                 Fsutil_HandleUnlock(parentHandlePtr);
  796.                 }
  797.                 *dirOffsetPtr = blockOffset + 
  798.                     dirBlockNum * FS_BLOCK_SIZE;
  799.                 /*
  800.                  * Inlined call to GetHandle().
  801.                  */
  802.                 fileID.type = FSIO_LCL_FILE_STREAM;
  803.                 fileID.serverID = rpc_SpriteID;
  804.                 fileID.major = parentHandlePtr->hdr.fileID.major;
  805.                 fileID.minor = dirEntryPtr->fileNumber;
  806.                 status = Fsio_LocalFileHandleInit(&fileID, component,
  807.                         (Fsdm_FileDescriptor *) NIL, FALSE,
  808.                         curHandlePtrPtr);
  809.  
  810.                 Fscache_UnlockBlock(cacheBlockPtr, (time_t) 0,
  811.                             -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  812.                 if (status == SUCCESS) {
  813.                 FSLCL_HASH_INSERT(fslclNameTablePtr, component,
  814.                          parentHandlePtr, *curHandlePtrPtr);
  815.                 } else {
  816.                 /*
  817.                  * It is possible that the file doesn't 
  818.                  * exist anymore.  This happens when
  819.                  * the parent directory of an open
  820.                  * directory is deleted.  The ".." entry
  821.                  * points to a deleted file.
  822.                  */
  823.                 if (status == FS_FILE_REMOVED) {
  824.                     status = FS_FILE_NOT_FOUND;
  825.                 } else {
  826.  
  827.                     printf(
  828.         "FindComponent, no handle <0x%x> for \"%s\" fileNumber %d\n",
  829.                     status, component, dirEntryPtr->fileNumber);
  830.                 }
  831.                 if (isDotDot) {
  832.                     /*
  833.                      * If we have an error, relock the handle
  834.                      * because your caller will assume that it
  835.                      * is locked.
  836.                      */
  837.                     Fsutil_HandleLock(parentHandlePtr);
  838.                 }
  839.                 }
  840.                 goto exit;    /* to quiet lint... */
  841. #ifndef lint
  842.             } else if (*s1++ != *s2++) {
  843.                 break;
  844. #else
  845.             } else {
  846.                 if (*s1 != *s2) {
  847.                 break;
  848.                 }
  849.                 s1++;
  850.                 s2++;
  851. #endif
  852.             }
  853.             } while (TRUE);
  854.         }
  855.         }
  856.         blockOffset += dirEntryPtr->recordLength;
  857.         dirEntryPtr = (Fslcl_DirEntry *)((int)dirEntryPtr +
  858.                      dirEntryPtr->recordLength);
  859.     }
  860.     dirBlockNum++;
  861.     Fscache_UnlockBlock(cacheBlockPtr, (time_t) 0, -1, 0, 0);
  862.     } while(TRUE);
  863. exit:
  864.     return(status);
  865. }
  866.  
  867.  
  868. /*
  869.  *----------------------------------------------------------------------
  870.  *
  871.  * InsertComponent --
  872.  *    Add a name to a directory.
  873.  *
  874.  * Results:
  875.  *    SUCCESS or an error code.
  876.  *
  877.  * Side effects:
  878.  *    Adding the name to the directory, writing the modified directory block.
  879.  *
  880.  *----------------------------------------------------------------------
  881.  */
  882. static ReturnStatus
  883. InsertComponent(curHandlePtr, component, compLen, fileNumber, dirOffsetPtr)
  884.     Fsio_FileIOHandle *curHandlePtr;    /* Locked handle of current directory */
  885.     char *component;            /* Name of path component to insert */
  886.     int compLen;            /* The length of component */
  887.     int fileNumber;            /* File Number of inserted name */
  888.     int    *dirOffsetPtr;  /* OUT: directory offset of component's entry.*/
  889. {
  890.     ReturnStatus     status;
  891.     int            dirBlockNum;    /* Directory block index */
  892.     int         blockOffset;    /* Offset within a directory block. */
  893.     Fslcl_DirEntry         *dirEntryPtr;    /* Reference to directory entry. */
  894.     int         length;        /* Length variable for read call. */
  895.     int         recordLength;    /* Length of directory entry for 
  896.                      * component. */
  897.     int         freeSpace;    /* Total amount of free bytes in a 
  898.                      * directory block. */
  899.     int         extraBytes;    /* The number of free bytes attached to
  900.                       * a directory entry. */
  901.     Fscache_Block    *cacheBlockPtr;    /* Cache block. */
  902.  
  903.     length = FS_BLOCK_SIZE;
  904.     recordLength = Fslcl_DirRecLength(compLen);
  905.     /*
  906.      * Loop through the directory blocks looking for space of at least
  907.      * recordLength in which to insert the new directory record.
  908.      */
  909.     dirBlockNum = 0;
  910.     do {
  911.     /*
  912.      * Read in a full data block.
  913.      */
  914.     status = Fscache_BlockRead(&curHandlePtr->cacheInfo, dirBlockNum,
  915.             &cacheBlockPtr, &length, FSCACHE_DIR_BLOCK, TRUE);
  916.     if (status != SUCCESS) {
  917.         printf( "InsertComponent: Read failed\n");
  918.         return(status);
  919.     } else if (length == 0) {
  920.         /*
  921.          * No more space, have to grow the directory.  First we
  922.          * need another cache block.
  923.          */
  924.         Boolean found = FALSE;
  925.  
  926.         Fscache_FetchBlock(&curHandlePtr->cacheInfo, dirBlockNum,
  927.                 FSCACHE_DIR_BLOCK, &cacheBlockPtr, &found);
  928.         if (found) {
  929.         panic( "InsertComponent found new dir block");
  930.         }
  931.         bzero(cacheBlockPtr->blockAddr, FS_BLOCK_SIZE);
  932.     }
  933.  
  934.     dirEntryPtr = (Fslcl_DirEntry *)cacheBlockPtr->blockAddr;
  935.     blockOffset = 0;
  936.     freeSpace = 0;
  937.     while (blockOffset < length) {
  938.         /*
  939.          * Scan a data block looking for deleted entries that are
  940.          * large enough to use, or for entries that contain enough extra
  941.          * bytes for the record we have to insert.  The amount of fragmented
  942.          * space is accumulated in freeSpace but compaction is not 
  943.          * implemented.
  944.          */
  945.         if (dirEntryPtr->fileNumber != 0) {
  946.         /*
  947.          * A valid directory record.
  948.          * Check the left-over bytes attached to this record.
  949.          */
  950.         extraBytes = dirEntryPtr->recordLength -
  951.                  Fslcl_DirRecLength(dirEntryPtr->nameLength);
  952.         if (extraBytes >= recordLength) {
  953.             /*
  954.              * Can fit new entry in the space left over.
  955.              */ 
  956.             goto haveASlot;
  957.         }
  958.         /*
  959.          * Count bytes that occur in fragments of 4 bytes or more.
  960.          */
  961.         freeSpace += extraBytes & ~(FSLCL_REC_LEN_GRAIN-1);
  962.         } else {
  963.         /*
  964.          * A deleted name in the directory.
  965.          */
  966.         if (dirEntryPtr->recordLength >= recordLength) {
  967.             goto haveASlot;
  968.         }
  969.         freeSpace += dirEntryPtr->recordLength;
  970.         }
  971.         blockOffset += dirEntryPtr->recordLength;
  972.         dirEntryPtr = (Fslcl_DirEntry *)((int)dirEntryPtr +
  973.                      dirEntryPtr->recordLength);
  974.     }
  975.     /*
  976.      * Finished scanning a directory block.  Note if the accumulated
  977.      * free bytes in the block could be used for a directory entry.
  978.      * (We aren't implementing compaction for a while yet...)
  979.      */
  980.     if (freeSpace >= recordLength) {
  981.         fsCompacts++;
  982.     }
  983.     if (length < FS_BLOCK_SIZE) {
  984.         /*
  985.          * Scanned up to the end of the last directory data block.  Need
  986.          * to append to the end of the directory.
  987.          */
  988.         bzero(cacheBlockPtr->blockAddr + length, FSLCL_DIR_BLOCK_SIZE);
  989.         dirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE;
  990.         length += FSLCL_DIR_BLOCK_SIZE;
  991.         break;
  992.     }
  993.  
  994.     dirBlockNum++;
  995.     Fscache_UnlockBlock(cacheBlockPtr,
  996.                         (time_t) 0, -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  997.     } while(TRUE);
  998.  
  999. haveASlot:
  1000.  
  1001.     /*
  1002.      * At this point dirEntryPtr references the slot we have to either re-use
  1003.      * or that has enough free bytes for us to use.
  1004.      */
  1005.     if (dirEntryPtr->fileNumber != 0) {
  1006.     /*
  1007.      * Have to take space away from the end of a valid directory entry.
  1008.      */
  1009.     int newRecordLength;    /* New length of the existing valid entry */
  1010.     Fslcl_DirEntry *tmpDirEntryPtr;    /* Pointer to new slot */
  1011.  
  1012.     newRecordLength = Fslcl_DirRecLength(dirEntryPtr->nameLength);
  1013.     tmpDirEntryPtr = (Fslcl_DirEntry *)((int)dirEntryPtr + newRecordLength);
  1014.     tmpDirEntryPtr->recordLength = dirEntryPtr->recordLength -
  1015.                        newRecordLength;
  1016.     dirEntryPtr->recordLength = newRecordLength;
  1017.     dirEntryPtr = tmpDirEntryPtr;
  1018.     }
  1019.     dirEntryPtr->fileNumber = fileNumber;
  1020.     dirEntryPtr->nameLength = compLen;
  1021.     (void)strcpy(dirEntryPtr->fileName, component);
  1022.  
  1023.     blockOffset = (((char *)dirEntryPtr) - (char *)(cacheBlockPtr->blockAddr));
  1024.     *dirOffsetPtr = dirBlockNum * FS_BLOCK_SIZE + blockOffset;
  1025.     status = CacheDirBlockWrite(curHandlePtr,cacheBlockPtr,dirBlockNum,length);
  1026.     return(status);
  1027. }
  1028.  
  1029.  
  1030. /*
  1031.  *----------------------------------------------------------------------
  1032.  *
  1033.  * DeleteComponent --
  1034.  *
  1035.  *    Delete a name from a directory.  The file descriptor itself
  1036.  *    is not modified.  It is assumed that the handle for the file that
  1037.  *    is being removed is already locked.
  1038.  *
  1039.  * Results:
  1040.  *    SUCCESS or FS_FILE_NOT_FOUND
  1041.  *
  1042.  * Side effects:
  1043.  *    Sets the fileNumber for the component to Zero (0) to mark as deleted.
  1044.  *
  1045.  *----------------------------------------------------------------------
  1046.  */
  1047. static ReturnStatus
  1048. DeleteComponent(parentHandlePtr, component, compLen, dirOffsetPtr)
  1049.     Fsio_FileIOHandle    *parentHandlePtr;/* Locked handle of current dir. */
  1050.     char         *component;    /* Name to delete */
  1051.     int         compLen;    /* Length of the name */
  1052.     int            *dirOffsetPtr;    /* OUT: Directory offset of component.*/
  1053. {
  1054.     ReturnStatus    status;
  1055.     int         blockOffset;    /* Offset within a directory block */
  1056.     Fslcl_DirEntry     *dirEntryPtr;    /* Reference to directory entry */
  1057.     Fslcl_DirEntry     *lastDirEntryPtr;/* Back pointer used when merging 
  1058.                       * adjacent entries after the delete */
  1059.     int         length;        /* Length variable for read call */
  1060.     Fscache_Block    *cacheBlockPtr;    /* Cache block. */
  1061.     int            dirBlockNum;
  1062.  
  1063.     dirBlockNum = 0;
  1064.     do {
  1065.     status = Fscache_BlockRead(&parentHandlePtr->cacheInfo, dirBlockNum,
  1066.               &cacheBlockPtr, &length, FSCACHE_DIR_BLOCK, FALSE);
  1067.     if (status != SUCCESS || length == 0) {
  1068.         return(FS_FILE_NOT_FOUND);
  1069.     }
  1070.     blockOffset = 0;
  1071.     lastDirEntryPtr = (Fslcl_DirEntry *)NIL;
  1072.     dirEntryPtr = (Fslcl_DirEntry *)cacheBlockPtr->blockAddr;
  1073.     while (blockOffset < length) {
  1074.         if ((dirEntryPtr->fileNumber != 0) &&
  1075.         (dirEntryPtr->nameLength == compLen) &&
  1076.         (strcmp(component, dirEntryPtr->fileName) == 0)) {
  1077.         /*
  1078.          * Delete the entry from the name cache.
  1079.          */
  1080.         *dirOffsetPtr = blockOffset + FS_BLOCK_SIZE*dirBlockNum;
  1081.         FSLCL_HASH_DELETE(fslclNameTablePtr, component,parentHandlePtr);
  1082.         dirEntryPtr->fileNumber = 0;
  1083.         if (lastDirEntryPtr != (Fslcl_DirEntry *)NIL) {
  1084.             /*
  1085.              * Grow the previous record so that it now includes
  1086.              * this one.
  1087.              */
  1088.             lastDirEntryPtr->recordLength += dirEntryPtr->recordLength;
  1089.         }
  1090.         /*
  1091.          * Write out the modified directory block.
  1092.          */
  1093.         status = CacheDirBlockWrite(parentHandlePtr, cacheBlockPtr, 
  1094.                        dirBlockNum, length);
  1095.         return(status);
  1096.         }
  1097.         blockOffset += dirEntryPtr->recordLength;
  1098.         if ((blockOffset & (FSLCL_DIR_BLOCK_SIZE - 1)) == 0) {
  1099.          lastDirEntryPtr = (Fslcl_DirEntry *) NIL;
  1100.         } else {
  1101.          lastDirEntryPtr = dirEntryPtr;
  1102.         }
  1103.         dirEntryPtr = 
  1104.         (Fslcl_DirEntry *)((int)dirEntryPtr + dirEntryPtr->recordLength);
  1105.     }
  1106.     dirBlockNum++;
  1107.     Fscache_UnlockBlock(cacheBlockPtr, (time_t) 0,
  1108.                         -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  1109.     } while(TRUE);
  1110.     /*NOTREACHED*/
  1111. }
  1112.  
  1113.  
  1114. /*
  1115.  *----------------------------------------------------------------------
  1116.  *
  1117.  * ExpandLink --
  1118.  *    Expand a link by shifting the remaining pathname over and
  1119.  *    inserting the contents of the link file.
  1120.  *
  1121.  * Results:
  1122.  *    None.
  1123.  *
  1124.  * Side effects:
  1125.  *    Expands the link into nameBuffer.
  1126.  *
  1127.  *----------------------------------------------------------------------
  1128.  */
  1129. static ReturnStatus
  1130. ExpandLink(curHandlePtr, curCharPtr, offset, nameBuffer)
  1131.     Fsio_FileIOHandle    *curHandlePtr;    /* Handle on the link file */
  1132.     char    *curCharPtr;        /* Points to beginning of the remaining
  1133.                      * name that has to be shifted */
  1134.     int        offset;            /* Offset of curCharPtr within its 
  1135.                      * buffer */
  1136.     char     nameBuffer[];        /* New buffer for the expanded name */
  1137. {
  1138.     ReturnStatus     status;
  1139.     int         linkNameLength;    /* The length of the name in the
  1140.                      * link NOT including the Null */
  1141.     register char     *srcPtr;
  1142.     register char     *dstPtr;
  1143.  
  1144.     linkNameLength = curHandlePtr->descPtr->lastByte;    /* + 1 */
  1145.     if (linkNameLength < 0) {                /* <= */
  1146.     return(FS_FILE_NOT_FOUND);
  1147.     }
  1148.     if (*curCharPtr == '\0') {
  1149.     /*
  1150.      * There is no pathname, just make sure the new name is Null terminated
  1151.      */
  1152.     nameBuffer[linkNameLength] = '\0';        /* still ok */
  1153.     } else {
  1154.     /*
  1155.      * Set up srcPtr to point to the start of the remaining pathname.
  1156.      * Set up dstPtr to point to just after where the link will be,
  1157.      * ie. just where the '/' is that separates the link value from
  1158.      * the remaining pathname.
  1159.      */
  1160.     srcPtr = curCharPtr;
  1161.     dstPtr = &nameBuffer[linkNameLength];
  1162.     if (linkNameLength < offset) {
  1163.         /*
  1164.          * The remaining name has to be shifted left.
  1165.          * For example, /first is a link to /usr (or /users).  With the
  1166.          * filename /first/abc, curCharPtr will point to the 'a' in "abc".
  1167.          * dstPtr points to the '\0' after "/usr".
  1168.          *
  1169.          *  / f i r s t / a b c \0        { current name, offset = 7 }
  1170.          *  / u s r \0            { link name, len = 4 }
  1171.          *  / u s e r s \0            {   or len = 6 }
  1172.          *  / u s r / a b c            { final result }
  1173.          *
  1174.          * Insert the separating '/' first, then start at the beginning
  1175.          * of the remaining name and copy it into the new buffer.
  1176.          */
  1177.         *dstPtr = '/';
  1178.         dstPtr++;
  1179.         for( ; ; ) {
  1180.         *dstPtr = *srcPtr;
  1181.             if (*srcPtr == '\0') {
  1182.             break;
  1183.         }
  1184.         dstPtr++;
  1185.         srcPtr++;
  1186.         }
  1187.     } else {
  1188.         /*
  1189.          * The remaining name has to be shifted right.
  1190.          * For example, /first is a link to /usr/tmp.  With the filename
  1191.          * /first/abc, curCharPtr will point to the 'a' in "abc".
  1192.          * dstPtr points to the '\0' after "/usr/tmp".
  1193.          *
  1194.          * / f i r s t / a b c \0        { current name, offset = 7 }
  1195.          * / u s r / t m p \0        { link name, len = 8 }
  1196.          * / u s r / t m p / a b c        { final result }
  1197.          * 
  1198.          * Zoom to the end of the name (adjusting dstPtr to account
  1199.          * for where the '/' will go) and then shift the name right.
  1200.          */
  1201.         dstPtr++;
  1202.         while (*srcPtr != '\0') {
  1203.         srcPtr++;
  1204.         dstPtr++;
  1205.         }
  1206.         while (srcPtr >= curCharPtr) {
  1207.         *dstPtr = *srcPtr;
  1208.         dstPtr--;
  1209.         srcPtr--;
  1210.         }
  1211.         *dstPtr = '/';
  1212.     }
  1213.     }
  1214.     /*
  1215.      * Read and insert the link name in front of the remaining name
  1216.      * that was just shifted over.
  1217.      */
  1218.     status = Fscache_Read(&curHandlePtr->cacheInfo, 0, nameBuffer, 0,
  1219.             &linkNameLength, (Sync_RemoteWaiter *)NIL);
  1220.     if ((status == SUCCESS) || (linkNameLength > 0)) { 
  1221.     (void)Fsdm_UpdateDescAttr(curHandlePtr, &curHandlePtr->cacheInfo.attr, 
  1222.             FSDM_FD_ACCESSTIME_DIRTY);
  1223.     }
  1224.  
  1225.     /*
  1226.      * FIX HERE to handle old sprite links that include a null.
  1227.      */
  1228. #ifdef notdef
  1229.     if (nameBuffer[linkNameLength-1] == '\0') {
  1230.     /*
  1231.      * Old Sprite link with trailing NULL.  Shift remaining name over
  1232.      * to the left one place.
  1233.      */
  1234.     dstPtr = &nameBuffer[linkNameLength-1];
  1235.     srcPtr = dstPtr + 1;
  1236.     while (*srcPtr != '\0') {
  1237.         *dstPtr++ = *srcPtr++;
  1238.     }
  1239.     *dstPtr = '\0'
  1240.     }
  1241. #endif /* notdef */
  1242.     return status;
  1243. }
  1244.  
  1245. /*
  1246.  *----------------------------------------------------------------------
  1247.  *
  1248.  * GetHandle --
  1249.  *
  1250.  *    Given a file number and the handle on the parent directotry,
  1251.  *    this routine returns a locked handle for the file.  This is a
  1252.  *    small layer on top of Fsio_LocalFileHandleInit that is oriented
  1253.  *    towards the needs of the lookup routines.
  1254.  *
  1255.  * Results:
  1256.  *    A return code.  If SUCCESS the returned handle is locked.
  1257.  *
  1258.  * Side effects:
  1259.  *    Calls Fsio_LocalFileHandleInit to set up the handle.
  1260.  *
  1261.  *----------------------------------------------------------------------
  1262.  */
  1263.  
  1264. static ReturnStatus
  1265. GetHandle(fileNumber, newDescPtr, curHandlePtr, name, newHandlePtrPtr)
  1266.     int        fileNumber;        /* Number of file to get handle for */
  1267.     Fsdm_FileDescriptor *newDescPtr;
  1268.     Fsio_FileIOHandle    *curHandlePtr;    /* Handle on file in the same domain */
  1269.     char    *name;            /* File name for error msgs */
  1270.     Fsio_FileIOHandle    **newHandlePtrPtr;/* Return, ref. to installed handle */
  1271. {
  1272.     register ReturnStatus status;
  1273.     Fs_FileID fileID;
  1274.  
  1275.     fileID.type = FSIO_LCL_FILE_STREAM;
  1276.     fileID.serverID = rpc_SpriteID;
  1277.     fileID.major = curHandlePtr->hdr.fileID.major;
  1278.     fileID.minor = fileNumber;
  1279.     status = Fsio_LocalFileHandleInit(&fileID, name, newDescPtr, FALSE,
  1280.         newHandlePtrPtr);
  1281.     return(status);
  1282. }
  1283.  
  1284. /*
  1285.  *----------------------------------------------------------------------
  1286.  *
  1287.  * CreateFile --
  1288.  *      Create a file by adding it do a directory and and initializing its
  1289.  *      file descriptor.  The caller has already allocated the fileNumber
  1290.  *      for the file.  The file descriptor is written to disk before the
  1291.  *    name is inserted into the directory.
  1292.  *
  1293.  * Results:
  1294.  *    SUCCESS or an error code.
  1295.  *
  1296.  * Side effects:
  1297.  *    Calls InsertComponent, Fsdm_FileDescInit.
  1298.  *
  1299.  *----------------------------------------------------------------------
  1300.  */
  1301. static ReturnStatus
  1302. CreateFile(domainPtr, parentHandlePtr, component, compLen, fileNumber, type,
  1303.        permissions, idPtr, curHandlePtrPtr, dirOffsetPtr)
  1304.     Fsdm_Domain    *domainPtr;        /* Domain of the file */
  1305.     Fsio_FileIOHandle    *parentHandlePtr;/* Handle of directory in which to add 
  1306.                      * file. */
  1307.     char    *component;        /* Name of the file */
  1308.     int        compLen;        /* The length of component */
  1309.     int        fileNumber;        /* Domain relative file number */
  1310.     int        type;            /* Type of the file */
  1311.     int        permissions;        /* Permission bits on the file */
  1312.     Fs_UserIDs    *idPtr;            /* User ID of calling process */
  1313.     Fsio_FileIOHandle    **curHandlePtrPtr;/* Return, handle for the new file */
  1314.     int        *dirOffsetPtr;  /* OUT: directory offset of component's entry.*/
  1315. {
  1316.     ReturnStatus    status;
  1317.     Fsdm_FileDescriptor    *parentDescPtr;    /* Descriptor for the parent */
  1318.     Fsdm_FileDescriptor    *newDescPtr;    /* Descriptor for the new file */
  1319.  
  1320.     /*
  1321.      * Set up the file descriptor using the group ID from the parent directory.
  1322.      */
  1323.     parentDescPtr = parentHandlePtr->descPtr;
  1324.     newDescPtr = (Fsdm_FileDescriptor *)malloc(sizeof(Fsdm_FileDescriptor));
  1325.     status = Fsdm_FileDescInit(domainPtr, fileNumber, type, permissions,
  1326.                 idPtr->user, parentDescPtr->gid, newDescPtr);
  1327.     if (status == SUCCESS) {
  1328.     if (type == FS_DIRECTORY) {
  1329.         /*
  1330.          * Both the parent and the directory itself reference it.
  1331.          */
  1332.         newDescPtr->numLinks = 2;
  1333.         newDescPtr->flags |= FSDM_FD_LINKS_DIRTY;
  1334.     }
  1335.     /*
  1336.      * GetHandle does extra work because we already have the
  1337.      * file descriptor all set up...
  1338.      */
  1339.     status = GetHandle(fileNumber, newDescPtr, parentHandlePtr, component,
  1340.                 curHandlePtrPtr);
  1341.     if (status != SUCCESS) {
  1342.         /*
  1343.          * GetHandle shouldn't fail because we just wrote out
  1344.          * the file descriptor.
  1345.          */
  1346.         panic( "CreateFile: GetHandle failed\n");
  1347.     } else {
  1348.         if (type == FS_DIRECTORY) {
  1349.         status = WriteNewDirectory(*curHandlePtrPtr,
  1350.                         parentHandlePtr);
  1351.         }
  1352.         if (status == SUCCESS) {
  1353.         /*
  1354.          * Commit by adding the name to the directory.  If we crash
  1355.          * after this the file will show up and have a good
  1356.          * descriptor for itself on disk.
  1357.          */
  1358.         status = InsertComponent(parentHandlePtr, component,
  1359.                       compLen, fileNumber, dirOffsetPtr);
  1360.         if (type == FS_DIRECTORY) {
  1361.             if (status == SUCCESS) {
  1362.             /*
  1363.              * Update the parent directory to reflect
  1364.              * the addition of a new sub-directory.
  1365.              */
  1366.             parentDescPtr->numLinks++;
  1367.             parentDescPtr->descModifyTime = Fsutil_TimeInSeconds();
  1368.             parentDescPtr->flags |= FSDM_FD_LINKS_DIRTY;
  1369.                (void)Fsdm_FileDescStore(parentHandlePtr, FALSE);
  1370.             }
  1371.         }
  1372.         }
  1373.         if (status != SUCCESS) {
  1374.         /*
  1375.          * Couldn't add to the directory, no disk space perhaps.
  1376.          * Unwind by marking the file descriptor as free and
  1377.          * releasing the handle we've created.
  1378.          */
  1379.         panic("CreateFile: aborting create of %d (%s) in %d\n",
  1380.             fileNumber, component, 
  1381.             parentHandlePtr->hdr.fileID.minor);
  1382.         newDescPtr->flags = FSDM_FD_FREE;
  1383.         Fsutil_HandleRelease(*curHandlePtrPtr, TRUE);
  1384.         *curHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  1385.         }
  1386.     }
  1387.     }
  1388.     if (status != SUCCESS)  { 
  1389.     free((Address) newDescPtr);
  1390.     } else {
  1391.        (void)Fsdm_FileDescStore(parentHandlePtr, FALSE);
  1392.     }
  1393.     return(status);
  1394. }
  1395.  
  1396.  
  1397. /*
  1398.  *----------------------------------------------------------------------
  1399.  *
  1400.  * WriteNewDirectory --
  1401.  *      Write a new sub-directory.  Set the file numbers on the canned image
  1402.  *      of a new directory and write the block to the directory.
  1403.  *
  1404.  * Results:
  1405.  *    SUCCESS or an error code.
  1406.  *
  1407.  * Side effects:
  1408.  *    Disk I/O to write the directory data block.
  1409.  *
  1410.  *----------------------------------------------------------------------
  1411.  */
  1412. static    ReturnStatus
  1413. WriteNewDirectory(curHandlePtr, parentHandlePtr)
  1414.     Fsio_FileIOHandle *curHandlePtr;        /* Handle of file to delete */
  1415.     Fsio_FileIOHandle *parentHandlePtr;    /* Handle of directory in which
  1416.                          * to delete file*/
  1417. {
  1418.     ReturnStatus    status;
  1419.     int            offset;
  1420.     int            length;
  1421.     register Fslcl_DirEntry *dirEntryPtr;
  1422.     char        *dirBlock;
  1423.  
  1424.     /*
  1425.      * The malloc and Byte_Copy could be avoided by puting this routine
  1426.      * into its own monitor so that it could write directly onto fslclEmptyDirBlock
  1427.      * fslclEmptyDirBlock is already set up with ".", "..", and the correct
  1428.      * nameLengths and recordLengths.
  1429.      */
  1430.     dirBlock = (char *)malloc(FSLCL_DIR_BLOCK_SIZE);
  1431.     bcopy((Address)fslclEmptyDirBlock, (Address)dirBlock, FSLCL_DIR_BLOCK_SIZE);
  1432.     dirEntryPtr = (Fslcl_DirEntry *)dirBlock;
  1433.     dirEntryPtr->fileNumber = curHandlePtr->hdr.fileID.minor;
  1434.     dirEntryPtr = (Fslcl_DirEntry *)((int)dirEntryPtr +
  1435.                  dirEntryPtr->recordLength);
  1436.     dirEntryPtr->fileNumber = parentHandlePtr->hdr.fileID.minor;
  1437.     offset = 0;
  1438.     length = FSLCL_DIR_BLOCK_SIZE;
  1439.     status = Fscache_Write(&curHandlePtr->cacheInfo, 0, (Address)dirBlock,
  1440.         offset, &length, (Sync_RemoteWaiter *)NIL);
  1441.     if (status == SUCCESS) {
  1442.     (void)Fsdm_UpdateDescAttr(curHandlePtr, &curHandlePtr->cacheInfo.attr, 
  1443.             FSDM_FD_MODTIME_DIRTY);
  1444.     }
  1445.     free(dirBlock);
  1446.     return(status);
  1447. }
  1448.  
  1449.  
  1450. /*
  1451.  *----------------------------------------------------------------------
  1452.  *
  1453.  * LinkFile --
  1454.  *    Create an entry in a directory that references an existing file.
  1455.  *    This understands that links to directories are made as part of
  1456.  *    a rename and checks that no circularities in the directory structure
  1457.  *    result from moving a directory.  Other than that it is left to
  1458.  *    the caller to check permissions.
  1459.  *
  1460.  * Results:
  1461.  *    SUCCESS or an error code.
  1462.  *
  1463.  * Side effects:
  1464.  *    Calls InsertComponent, bumps the link count on the existing file.
  1465.  *    Calls MoveDirectory in the case of directories.
  1466.  *
  1467.  *----------------------------------------------------------------------
  1468.  */
  1469. static ReturnStatus
  1470. LinkFile(parentHandlePtr, component, compLen, fileNumber, logOp,curHandlePtrPtr,
  1471.     clientID)
  1472.     Fsio_FileIOHandle    *parentHandlePtr;/* Handle of directory in which to add 
  1473.                      * file. */
  1474.     char    *component;        /* Name of the file */
  1475.     int        compLen;        /* The length of component */
  1476.     int        fileNumber;        /* Domain relative file number */
  1477.     int        logOp;
  1478.     Fsio_FileIOHandle    **curHandlePtrPtr;/* Return, handle for the new file */
  1479.     int        clientID;        /* ID of requesting client. */
  1480. {
  1481.     ReturnStatus    status;
  1482.     Fsdm_FileDescriptor    *linkDescPtr;    /* Descriptor for the existing file */
  1483.     Time         modTime;    /* Descriptors are modified */
  1484.     ClientData        logClientData;
  1485.     ClientData        recovLogClientData = (ClientData) 0;
  1486.     int            dirOffset;
  1487.  
  1488.     if (fileNumber == parentHandlePtr->hdr.fileID.minor) {
  1489.     /*
  1490.      * Trying to move a directory into itself, ie. % mv subdir subdir
  1491.      */
  1492.     return(GEN_INVALID_ARG);
  1493.     }
  1494.     status = GetHandle(fileNumber, (Fsdm_FileDescriptor *) NIL,
  1495.             parentHandlePtr, component, curHandlePtrPtr);
  1496.     if (status != SUCCESS) {
  1497.     printf( "LinkFile: can't get existing file handle\n");
  1498.     return(FAILURE);
  1499.     } else if ((*curHandlePtrPtr)->descPtr->fileType == FS_DIRECTORY) {
  1500.     logOp |= FSDM_LOG_IS_DIRECTORY;
  1501.     status = OkToMoveDirectory(parentHandlePtr, *curHandlePtrPtr);
  1502.     }
  1503.     if (status == SUCCESS) {
  1504.     linkDescPtr = (*curHandlePtrPtr)->descPtr;
  1505.     logClientData = Fsdm_DirOpStart(logOp, parentHandlePtr, -1,
  1506.                 component, compLen, fileNumber, 
  1507.                     linkDescPtr->fileType,
  1508.                     linkDescPtr);
  1509.     if (recov_Transparent && clientID != rpc_SpriteID) {
  1510.         recovLogClientData = Fsrecov_DirOpStart(logOp, parentHandlePtr, -1,
  1511.             component, compLen, fileNumber, 
  1512.             linkDescPtr->fileType, linkDescPtr);
  1513.     }
  1514.     linkDescPtr->numLinks++;
  1515.     linkDescPtr->descModifyTime = Fsutil_TimeInSeconds();
  1516.     linkDescPtr->flags |= FSDM_FD_LINKS_DIRTY;
  1517.     status = Fsdm_FileDescStore(*curHandlePtrPtr, FALSE);
  1518.     if (status == SUCCESS) {
  1519.         /*
  1520.          * Commit by adding the name to the directory.
  1521.          */
  1522.         status = InsertComponent(parentHandlePtr, component, compLen,
  1523.                         fileNumber, &dirOffset);
  1524.         if ((*curHandlePtrPtr)->descPtr->fileType == FS_DIRECTORY &&
  1525.         status == SUCCESS) {
  1526.         /*
  1527.          * This link is part of a rename (links to directories are
  1528.          * only allowed at this time), and the ".." entry in the
  1529.          * directory may have to be fixed.
  1530.          */
  1531.         modTime.seconds = Fsutil_TimeInSeconds();
  1532.         status = MoveDirectory(&modTime, parentHandlePtr,
  1533.                             *curHandlePtrPtr);
  1534.         if (status != SUCCESS) {
  1535.             (void)DeleteComponent(parentHandlePtr, component,
  1536.                             compLen, &dirOffset);
  1537.         }
  1538.         }
  1539.         if (status != SUCCESS) {
  1540.         /*
  1541.          * Couldn't add to the directory because of I/O probably.
  1542.          * Unwind by reducing the link count.  This gets the cache
  1543.          * consistent with the cached directory image anyway.
  1544.          */
  1545.         linkDescPtr->numLinks--;
  1546.         linkDescPtr->flags |= FSDM_FD_LINKS_DIRTY;
  1547.         (void)Fsdm_FileDescStore(*curHandlePtrPtr, FALSE);
  1548.         Fsutil_HandleRelease(*curHandlePtrPtr, TRUE);
  1549.         *curHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  1550.         } else {
  1551.         (void)Fsdm_FileDescStore(parentHandlePtr, FALSE);
  1552.         }
  1553.     } else {
  1554.         linkDescPtr->numLinks--;
  1555.         linkDescPtr->flags &= ~FSDM_FD_LINKS_DIRTY;
  1556.     }
  1557.     Fsdm_DirOpEnd(logOp, parentHandlePtr, dirOffset, 
  1558.           component, compLen, fileNumber, linkDescPtr->fileType,
  1559.           linkDescPtr, logClientData, status);
  1560.     if (recov_Transparent && clientID != rpc_SpriteID) {
  1561.         Fsrecov_DirOpEnd(logOp, parentHandlePtr, dirOffset, 
  1562.             component, compLen, fileNumber, linkDescPtr->fileType,
  1563.             linkDescPtr, recovLogClientData, status);
  1564.     }
  1565.     }
  1566.     return(status);
  1567. }
  1568.  
  1569.  
  1570. /*
  1571.  *----------------------------------------------------------------------
  1572.  *
  1573.  * OkToMoveDirectory --
  1574.  *
  1575.  *    Check that it is ok to move a directory.  Dis-connected trees and
  1576.  *    loops in directory structure are prevented here.
  1577.  *
  1578.  * Results:
  1579.  *    A return code.
  1580.  *
  1581.  * Side effects:
  1582.  *    File handles are momentarily locked on the route from the new
  1583.  *    position in the hierarchy up to the root to check against illegal moves.
  1584.  *    This action might cause deadlock with another process desending along
  1585.  *    same route, descenders hold a lock on the parent while they try for
  1586.  *    a lock on the next sub-directory.
  1587.  *
  1588.  *----------------------------------------------------------------------
  1589.  */
  1590. static ReturnStatus
  1591. OkToMoveDirectory(newParentHandlePtr, curHandlePtr)
  1592.     Fsio_FileIOHandle *newParentHandlePtr;    /* New parent directory for
  1593.                          * curHandlePtr */
  1594.     Fsio_FileIOHandle *curHandlePtr;        /* Directory being moved */
  1595. {
  1596.     ReturnStatus    status;
  1597.     int         oldParentFileNumber;    /* File number of original 
  1598.                          * parent directory. */
  1599.     int            newParentNumber;    /* File number of new 
  1600.                          * parent directory. */
  1601.  
  1602.     status = GetParentNumber(curHandlePtr, &oldParentFileNumber);
  1603.     if (status != SUCCESS) {
  1604.     return(status);
  1605.     }
  1606.     newParentNumber = newParentHandlePtr->hdr.fileID.minor;
  1607.     if (oldParentFileNumber == newParentNumber) {
  1608.     /*
  1609.      * ".." entry is ok because the rename is within the same directory.
  1610.      */
  1611.     status = SUCCESS;
  1612.     } else {
  1613.     /*
  1614.      * Have to trace up from the new parent to make sure we don't find
  1615.      * the current file.  If we let that happen then you create
  1616.      * dis-connected loops in the directory structure.
  1617.      */
  1618.     Fsio_FileIOHandle *parentHandlePtr;
  1619.     int parentNumber;
  1620.  
  1621.     for (parentNumber = newParentNumber; status == SUCCESS; ) {
  1622.         if (parentNumber == curHandlePtr->hdr.fileID.minor) {
  1623.         status = FS_INVALID_ARG;
  1624.         } else if (parentNumber == FSDM_ROOT_FILE_NUMBER ||
  1625.                parentNumber == oldParentFileNumber) {
  1626.         break;
  1627.         } else {
  1628.         /*
  1629.          * Advance parentNumber upwards towards the root.  The
  1630.          * handles are locked because of the I/O required to get
  1631.          * the parent file number.  We have to be careful when
  1632.          * locking the parents because the first parent
  1633.          * (newParentHandlePtr) is already locked by us.
  1634.          *
  1635.          * It still seems like there is a possibility of deadlock if
  1636.          * someone is desending into newParentHandlePtr and has a lock
  1637.          * on the directory above that.  FIX ME
  1638.          */
  1639.         if (parentNumber != newParentNumber) {
  1640.             status = GetHandle(parentNumber,
  1641.                (Fsdm_FileDescriptor *) NIL,   curHandlePtr, (char *)NIL,
  1642.                     &parentHandlePtr);
  1643.         } else {
  1644.             parentHandlePtr = newParentHandlePtr;
  1645.         }
  1646.         if (status == SUCCESS) {
  1647.             status = GetParentNumber(parentHandlePtr, &parentNumber);
  1648.         }
  1649.         if (parentHandlePtr != newParentHandlePtr) {
  1650.             (void)Fsutil_HandleRelease(parentHandlePtr, TRUE);
  1651.         }
  1652.         }
  1653.     }
  1654.     }
  1655.     return(status);
  1656. }
  1657.  
  1658.  
  1659. /*
  1660.  *----------------------------------------------------------------------
  1661.  *
  1662.  * MoveDirectory --
  1663.  *
  1664.  *    Complete the moving of a directory by updating its reference to
  1665.  *    its parent and incrementing the link count on its new parent.
  1666.  *
  1667.  * Results:
  1668.  *    A return code.
  1669.  *
  1670.  * Side effects:
  1671.  *    Sets the directory's parent entry to reference the parent passed in.
  1672.  *    Increments the link count on the new parent.
  1673.  *
  1674.  *----------------------------------------------------------------------
  1675.  */
  1676. static ReturnStatus
  1677. MoveDirectory( modTimePtr, newParentHandlePtr, curHandlePtr)
  1678.     Time    *modTimePtr;            /* Modify time for parent */
  1679.     Fsio_FileIOHandle    *newParentHandlePtr;    /* New parent directory for 
  1680.                          * curHandlePtr */
  1681.     Fsio_FileIOHandle    *curHandlePtr;        /* Directory being moved */
  1682. {
  1683.     ReturnStatus    status;
  1684.     int            oldParentFileNumber;    /* File number of original 
  1685.                          * parent directory */
  1686.     int            newParentNumber;    /* File number of new 
  1687.                          * parent directory */
  1688.  
  1689.     status = GetParentNumber(curHandlePtr, &oldParentFileNumber);
  1690.     if (status != SUCCESS) {
  1691.     printf(
  1692.           "MoveDirectory: Can't get parent's file number\n");
  1693.     } else {
  1694.     newParentNumber = newParentHandlePtr->hdr.fileID.minor;
  1695.     if (oldParentFileNumber != newParentNumber) {
  1696.         /*
  1697.          * Patch the directory entry for ".."
  1698.          */
  1699.         FSLCL_HASH_DELETE(fslclNameTablePtr, "..", curHandlePtr);
  1700.         status = SetParentNumber(curHandlePtr, newParentNumber);
  1701.     }
  1702.     if (status == SUCCESS) {
  1703.         /*
  1704.          * Increment the link count on the new parent.  The old parent's
  1705.          * link count gets decremented when the orignial instance of the
  1706.          * directory is removed.  This is done even if the move is within
  1707.          * the same directory because deleting the original name later will
  1708.          * reduce the link count.
  1709.          */
  1710.         register Fsdm_FileDescriptor *parentDescPtr;
  1711.  
  1712.         parentDescPtr = newParentHandlePtr->descPtr;
  1713.         parentDescPtr->numLinks++;
  1714.         parentDescPtr->descModifyTime = modTimePtr->seconds;
  1715.         parentDescPtr->flags |= FSDM_FD_LINKS_DIRTY;
  1716.         (void)Fsdm_FileDescStore(newParentHandlePtr, FALSE);
  1717.     }
  1718.     }
  1719.     return(status);
  1720. }
  1721.  
  1722.  
  1723. /*
  1724.  *----------------------------------------------------------------------
  1725.  *
  1726.  * GetParentNumber --
  1727.  *    Read a directory to determine the file number of the parent.
  1728.  *
  1729.  * Results:
  1730.  *    SUCCESS or an error code, sets *parentNumberPtr to be the file number
  1731.  *    from the ".." entry in the directory.
  1732.  *
  1733.  * Side effects:
  1734.  *    None, except for the I/O to read the directory block.
  1735.  *
  1736.  *----------------------------------------------------------------------
  1737.  */
  1738. static ReturnStatus
  1739. GetParentNumber(curHandlePtr, parentNumberPtr)
  1740.     Fsio_FileIOHandle    *curHandlePtr;    /* Handle for current directory */
  1741.     int        *parentNumberPtr;    /* Result, the file number of the parent
  1742.                      * of curHandlePtr */
  1743. {
  1744.     ReturnStatus     status;
  1745.     int         length;
  1746.     register Fslcl_DirEntry *dirEntryPtr;
  1747.     Fscache_Block    *cacheBlockPtr;
  1748.  
  1749.     status = Fscache_BlockRead(&curHandlePtr->cacheInfo, 0, &cacheBlockPtr,
  1750.                 &length, FSCACHE_DIR_BLOCK, FALSE);
  1751.     if (status != SUCCESS) {
  1752.     return(status);
  1753.     } else if (length == 0) {
  1754.     return(FAILURE);
  1755.     }
  1756.  
  1757.     dirEntryPtr = (Fslcl_DirEntry *)cacheBlockPtr->blockAddr;
  1758.     if (dirEntryPtr->nameLength != 1 ||
  1759.     dirEntryPtr->fileName[0] != '.' ||
  1760.     dirEntryPtr->fileName[1] != '\0') {
  1761.     printf(
  1762.           "GetParentNumber: \".\", corrupted directory\n");
  1763.     status = FAILURE;
  1764.     } else {
  1765.     dirEntryPtr = 
  1766.         (Fslcl_DirEntry *)((int)dirEntryPtr + dirEntryPtr->recordLength);
  1767.     if (dirEntryPtr->nameLength != 2 ||
  1768.         dirEntryPtr->fileName[0] != '.' ||
  1769.         dirEntryPtr->fileName[1] != '.' ||
  1770.         dirEntryPtr->fileName[2] != '\0') {
  1771.         printf(
  1772.               "GetParentNumber: \"..\", corrupted directory\n");
  1773.         status = FAILURE;
  1774.     } else {
  1775.         *parentNumberPtr = dirEntryPtr->fileNumber;
  1776.     }
  1777.     }
  1778.     Fscache_UnlockBlock(cacheBlockPtr, (time_t) 0,
  1779.                     -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  1780.  
  1781.     return(status);
  1782. }
  1783.  
  1784.  
  1785. /*
  1786.  *----------------------------------------------------------------------
  1787.  *
  1788.  * SetParentNumber --
  1789.  *    Patch the file number for the ".." entry of a directory.
  1790.  *
  1791.  * Results:
  1792.  *    SUCCESS or an error code from the I/O.
  1793.  *
  1794.  * Side effects:
  1795.  *    Changes the parent file number of the ".." entry.
  1796.  *
  1797.  *----------------------------------------------------------------------
  1798.  */
  1799. static ReturnStatus
  1800. SetParentNumber(curHandlePtr, newParentNumber)
  1801.     Fsio_FileIOHandle    *curHandlePtr;    /* Handle for current directory */
  1802.     int         newParentNumber;/* The new file number of the parent
  1803.                      * of curHandlePtr */
  1804. {
  1805.     ReturnStatus    status;
  1806.     int         length;
  1807.     register Fslcl_DirEntry *dirEntryPtr;
  1808.     Fscache_Block    *cacheBlockPtr;
  1809.  
  1810.     status = Fscache_BlockRead(&curHandlePtr->cacheInfo, 0, &cacheBlockPtr,
  1811.                 &length, FSCACHE_DIR_BLOCK, FALSE);
  1812.     if (status != SUCCESS) {
  1813.     return(status);
  1814.     } else if (length == 0) {
  1815.     return(FAILURE);
  1816.     }
  1817.     dirEntryPtr = (Fslcl_DirEntry *)cacheBlockPtr->blockAddr;
  1818.     if (dirEntryPtr->nameLength != 1 ||
  1819.     dirEntryPtr->fileName[0] != '.' ||
  1820.     dirEntryPtr->fileName[1] != '\0') {
  1821.     printf(
  1822.           "SetParentNumber: \".\", corrupted directory\n");
  1823.     Fscache_UnlockBlock(cacheBlockPtr, (time_t) 0,
  1824.                         -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  1825.     return(FAILURE);
  1826.     }
  1827.     dirEntryPtr = (Fslcl_DirEntry *)((int)dirEntryPtr + dirEntryPtr->recordLength);
  1828.     if (dirEntryPtr->nameLength != 2 ||
  1829.     dirEntryPtr->fileName[0] != '.' ||
  1830.     dirEntryPtr->fileName[1] != '.' ||
  1831.     dirEntryPtr->fileName[2] != '\0') {
  1832.     printf("SetParentNumber: \"..\", corrupted directory\n");
  1833.     Fscache_UnlockBlock(cacheBlockPtr, (time_t) 0,
  1834.                         -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  1835.     return(FAILURE);
  1836.     }
  1837.     dirEntryPtr->fileNumber = newParentNumber;
  1838.     status = CacheDirBlockWrite(curHandlePtr, cacheBlockPtr, 0, length);
  1839.     return(status);
  1840. }
  1841.  
  1842.  
  1843. /*
  1844.  *----------------------------------------------------------------------
  1845.  *
  1846.  * DeleteFileName --
  1847.  *
  1848.  *      Delete a file by clearing its fileNumber in the directory and
  1849.  *    reducing its link count.  
  1850.  *
  1851.  * Results:
  1852.  *    SUCCESS or an error code.
  1853.  *
  1854.  * Side effects:
  1855.  *    Log entry may be written.
  1856.  *
  1857.  *----------------------------------------------------------------------
  1858.  */
  1859. static ReturnStatus
  1860. DeleteFileName(parentHandlePtr, curHandlePtr, component,
  1861.          compLen, forRename, idPtr, logOp, clientID)
  1862.     Fsio_FileIOHandle *parentHandlePtr;    /* Handle of directory in
  1863.                          * which to delete file*/
  1864.     Fsio_FileIOHandle *curHandlePtr;    /* Handle of file to delete */
  1865.     char *component;                /* Name of the file to delte */
  1866.     int compLen;                /* The length of component */
  1867.     int forRename;        /* if FS_RENAME, then the file being delted
  1868.                  * is being renamed.  This allows non-empty
  1869.                  * directories to be deleted */
  1870.     Fs_UserIDs *idPtr;        /* User and group IDs */
  1871.     int        logOp;        /* Directory log operation.; */
  1872.     int        clientID;
  1873. {
  1874.     ReturnStatus status;
  1875.     Fsdm_FileDescriptor *parentDescPtr;    /* Descriptor for parent */
  1876.     Fsdm_FileDescriptor *curDescPtr;    /* Descriptor for the file to delete */
  1877.     int type;                /* Type of the file */
  1878.     int    fileNumber;            /* Number of file being deleted. */
  1879.     ClientData    logClientData;        /* ClientData returned from 
  1880.                      * DirOpStart. */
  1881.     ClientData    recovLogClientData = (ClientData) 0;
  1882.                     /* ClientData returned from 
  1883.                      * DirOpStart, for recovery system. */
  1884.     int dirOffset;
  1885.  
  1886.     type = curHandlePtr->descPtr->fileType;
  1887.     if (parentHandlePtr == (Fsio_FileIOHandle *)NIL) {
  1888.     /*
  1889.      * There is no handle on the parent because we have just
  1890.      * gone up via "..".  You can't delete the parent.
  1891.      */
  1892.     status = FS_NO_ACCESS;
  1893.     } else if ((compLen == 1) && (component[0] == '.')) {
  1894.     /*
  1895.      * Disallow removing dot.
  1896.      */
  1897.     status = FS_NO_ACCESS;
  1898.     } else if (type == FS_DIRECTORY && (!forRename) &&
  1899.         !DirectoryEmpty(curHandlePtr)) {
  1900.     status = FS_DIR_NOT_EMPTY;
  1901.     } else {
  1902.     /*
  1903.      * One needs write permission in the parent to do the delete.
  1904.      */
  1905.     status = CheckPermissions(parentHandlePtr, FS_WRITE, idPtr,
  1906.                     FS_DIRECTORY);
  1907.     }
  1908.     if (status != SUCCESS) {
  1909.     return(status);
  1910.     }
  1911.     curDescPtr = curHandlePtr->descPtr;
  1912.     parentDescPtr = parentHandlePtr->descPtr;
  1913.     fileNumber = curHandlePtr->hdr.fileID.minor;
  1914.     dirOffset = -1;
  1915.  
  1916.     if (type == FS_DIRECTORY) {
  1917.     logOp |= FSDM_LOG_IS_DIRECTORY;
  1918.     }
  1919.     logClientData = Fsdm_DirOpStart(logOp, parentHandlePtr, dirOffset, 
  1920.             component, compLen, fileNumber, type,
  1921.             curHandlePtr->descPtr);
  1922.     if (recov_Transparent && clientID != rpc_SpriteID) {
  1923.     recovLogClientData = Fsrecov_DirOpStart(logOp, parentHandlePtr,
  1924.         dirOffset, component, compLen, fileNumber, type,
  1925.         curHandlePtr->descPtr);
  1926.     }
  1927.     /*
  1928.      * Remove the name from the directory first.
  1929.      */
  1930.     status = DeleteComponent(parentHandlePtr, component, compLen, &dirOffset);
  1931.     if (status == SUCCESS) {
  1932.     curDescPtr->numLinks--;
  1933.     curDescPtr->flags |= FSDM_FD_LINKS_DIRTY;
  1934.     if (type == FS_DIRECTORY) {
  1935.         /*
  1936.          * The directory might have been known in the hash table as
  1937.          * someone's "..". Besure that this entry is gone.
  1938.          */
  1939.         FSLCL_HASH_DELETE(fslclNameTablePtr, "..", curHandlePtr);
  1940.         if (!forRename) {
  1941.         /*
  1942.          * Directories have an extra link because they reference 
  1943.          * themselves.
  1944.          */
  1945.         curDescPtr->numLinks--;
  1946.         if (curDescPtr->numLinks > 0) {
  1947.             printf("DeleteFileName: extra links on directory\n");
  1948.         }
  1949.         }
  1950.     }
  1951.     curDescPtr->descModifyTime = Fsutil_TimeInSeconds();
  1952.     status = Fsdm_FileDescStore(curHandlePtr, FALSE);
  1953.     if (status != SUCCESS) {
  1954.         printf("DeleteFileName: (1) Couldn't store descriptor\n");
  1955. #ifdef notdef
  1956.         return(status);
  1957. #endif
  1958.     }
  1959.     if (type == FS_DIRECTORY) {
  1960.         /*
  1961.          * A directory's link count reflects the number of subdirectories
  1962.          * it has (they each have a ".." that references it.)  Here
  1963.          * it is decremented because the subdirectory is going away.
  1964.          */
  1965.         parentDescPtr->numLinks--;
  1966.         parentDescPtr->descModifyTime = Fsutil_TimeInSeconds();
  1967.         parentDescPtr->flags |= FSDM_FD_LINKS_DIRTY;
  1968.     }
  1969.     status = Fsdm_FileDescStore(parentHandlePtr, FALSE);
  1970.     if (status != SUCCESS) {
  1971.         printf("DeleteFileName: (2) Couldn't store descriptor\n");
  1972. #ifdef notdef
  1973.         return(status);
  1974. #endif
  1975.     }
  1976.     if ((curDescPtr->numLinks <= 0) && (curHandlePtr->use.ref != 0)) {
  1977.         logOp |= FSDM_LOG_STILL_OPEN;
  1978.     }
  1979.     } 
  1980.     Fsdm_DirOpEnd(logOp, parentHandlePtr, dirOffset,
  1981.                 component, compLen, fileNumber, type,
  1982.             curDescPtr, logClientData, status);
  1983.     if (recov_Transparent && clientID != rpc_SpriteID) {
  1984.     Fsrecov_DirOpEnd(logOp, parentHandlePtr, dirOffset,
  1985.         component, compLen, fileNumber, type,
  1986.         curDescPtr, recovLogClientData, status);
  1987.     }
  1988.     return(status);
  1989. }
  1990.  
  1991. /*
  1992.  *----------------------------------------------------------------------
  1993.  *
  1994.  * CloseDeletedFile --
  1995.  *
  1996.  *    This routine is called to close a deleted file.
  1997.  *    If there are no links left then the
  1998.  *    file's handle is marked as deleted.  Finally, if this routine
  1999.  *    has the last reference on the handle then the file's data blocks
  2000.  *    are truncated away and the file descriptor is marked as free.
  2001.  *
  2002.  *    This is a separate routine from DeleteFileName because the
  2003.  *    file cannot be closed unless the parent handle is unlocked
  2004.  *    (to prevent deadlock while doing the consistency callback),
  2005.  *    and the code to do a rename deletes the existing file, then
  2006.  *    does a link.  This would break if the parent handle was
  2007.  *    released during the delete.
  2008.  *
  2009.  * Results:
  2010.  *    SUCCESS or error code.
  2011.  *
  2012.  * Side effects:
  2013.  *    The parent and/or current handles may be released and set to NIL.
  2014.  *
  2015.  *----------------------------------------------------------------------
  2016.  */
  2017.  
  2018. static void
  2019. CloseDeletedFile(parentHandlePtrPtr, curHandlePtrPtr)
  2020.     Fsio_FileIOHandle **parentHandlePtrPtr;    /* Handle of parent of
  2021.                          * deleted file. */
  2022.     Fsio_FileIOHandle **curHandlePtrPtr;    /* Handle of deleted file. */
  2023.  
  2024. {
  2025.     register Fsio_FileIOHandle *curHandlePtr;    /* Local copy */
  2026.  
  2027.     curHandlePtr = *curHandlePtrPtr;
  2028.     if (curHandlePtr->descPtr->numLinks <= 0) {
  2029.     /*
  2030.      * At this point curHandlePtr is potentially the last reference
  2031.      * to the file.  If there are no users then do the delete, otherwise
  2032.      * mark the handle as deleted and Fsio_FileClose will take care of 
  2033.      * it.
  2034.      */
  2035.     curHandlePtr->flags |= FSIO_FILE_NAME_DELETED;
  2036.     if (curHandlePtr->use.ref == 0) {
  2037.         /*
  2038.          * Handle the deletion and clean up the handle.
  2039.          * We set the the clientID to us and specify client
  2040.          * call-backs so that any other clients will be notified.
  2041.          */
  2042.         Fsutil_HandleRelease(*parentHandlePtrPtr, TRUE);
  2043.         *parentHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  2044.         (void)Fsio_FileCloseInt(curHandlePtr, 0, 0, 0, rpc_SpriteID, 
  2045.             TRUE);
  2046.         *curHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  2047.     } else {
  2048.         Fsutil_HandleRelease(curHandlePtr, TRUE);
  2049.         *curHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  2050.     }
  2051.     } else {
  2052.     Fsutil_HandleRelease(curHandlePtr, TRUE);
  2053.     *curHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  2054.     }
  2055. }
  2056.  
  2057.  
  2058. /*
  2059.  *----------------------------------------------------------------------
  2060.  *
  2061.  * Fslcl_DeleteFileDesc --
  2062.  *    Delete a file from disk given its file handle.  It is assumed that the
  2063.  *    file's name has already been deleted from the directory structure.
  2064.  *
  2065.  * Results:
  2066.  *    None.
  2067.  *
  2068.  * Side effects:
  2069.  *    Delete the data blocks and mark file descriptor as free.  The
  2070.  *    handle remains locked during this call.  The DESCRIPTOR referenced
  2071.  *    by the handle is FREED because the file handle is going to
  2072.  *    be removed.
  2073.  *
  2074.  *----------------------------------------------------------------------
  2075.  */
  2076.  
  2077. ReturnStatus
  2078. Fslcl_DeleteFileDesc(handlePtr)
  2079.     Fsio_FileIOHandle *handlePtr;
  2080. {
  2081.     ReturnStatus status;
  2082.     Fsdm_Domain *domainPtr;
  2083.  
  2084.     if (handlePtr->descPtr->fileType == FS_DIRECTORY) {
  2085.     /*
  2086.      * Remove .. from the name cache so we don't end up with
  2087.      * a bad cache entry later when this directory is re-created.
  2088.      */
  2089.     FSLCL_HASH_DELETE(fslclNameTablePtr, "..", handlePtr);
  2090.     }
  2091.  
  2092.     domainPtr = Fsdm_DomainFetch(handlePtr->hdr.fileID.major, FALSE);
  2093.     if (domainPtr == (Fsdm_Domain *)NIL) {
  2094.     return(FS_DOMAIN_UNAVAILABLE);
  2095.     }
  2096.     /*
  2097.      * The ordering of the deletion is as follows:
  2098.      * 1. Mark the descriptor on disk as free so if we crash the
  2099.      *        disk scavenger will free the blocks for us.
  2100.      * 2. Truncate the blocks out of the cache and from the descriptor.
  2101.      * 3. Mark the file descriptor as available in the bitmask.
  2102.      */
  2103.     handlePtr->descPtr->flags = FSDM_FD_FREE | FSDM_FD_DIRTY;
  2104.     status = Fsdm_FileDescStore(handlePtr,TRUE);
  2105.     if (status != SUCCESS) {
  2106.     printf("Fslcl_DeleteFileDesc: Can't mark descriptor as free\n");
  2107.     } else {
  2108.     status = Fsio_FileTrunc(handlePtr, 0, FSCACHE_TRUNC_DELETE);
  2109.     if (status != SUCCESS) {
  2110.         printf("Fslcl_DeleteFileDesc: Can't truncate file <%d,%d> \"%s\"\n",
  2111.             handlePtr->hdr.fileID.major, handlePtr->hdr.fileID.minor,
  2112.             Fsutil_HandleName(handlePtr));
  2113.     } else {
  2114.         (void)Fsdm_FreeFileNumber(domainPtr, handlePtr->hdr.fileID.minor);
  2115.     }
  2116.     free((Address)handlePtr->descPtr);
  2117.     handlePtr->descPtr = (Fsdm_FileDescriptor *)NIL;
  2118.     }
  2119.     Fsdm_DomainRelease(handlePtr->hdr.fileID.major);
  2120.     return(status);
  2121. }
  2122.  
  2123. /*
  2124.  *----------------------------------------------------------------------
  2125.  *
  2126.  * DirectoryEmpty --
  2127.  *    Scan a directory and determine if there are any files left
  2128.  *    in it other than "." and "..".
  2129.  *
  2130.  * Results:
  2131.  *    TRUE if the directory is empty, FALSE otherwise.
  2132.  *
  2133.  * Side effects:
  2134.  *    None.
  2135.  *
  2136.  *----------------------------------------------------------------------
  2137.  */
  2138.  
  2139. static Boolean
  2140. DirectoryEmpty(handlePtr)
  2141.     Fsio_FileIOHandle *handlePtr;    /* Handle of directory to check */
  2142. {
  2143.     ReturnStatus    status;
  2144.     int         blockOffset;    /* Offset within a directory block */
  2145.     Fslcl_DirEntry         *dirEntryPtr;    /* Reference to directory entry */
  2146.     int         length;        /* Length for read call */
  2147.     int            dirBlockNum;
  2148.     Fscache_Block    *cacheBlockPtr;
  2149.  
  2150.     dirBlockNum = 0;
  2151.     do {
  2152.     status = Fscache_BlockRead(&handlePtr->cacheInfo, dirBlockNum,
  2153.               &cacheBlockPtr, &length, FSCACHE_DIR_BLOCK, FALSE);
  2154.     if (status != SUCCESS || length == 0) {
  2155.         /*
  2156.          * Have run out of the directory and not found anything.
  2157.          */
  2158.         return(TRUE);
  2159.     }
  2160.     blockOffset = 0;
  2161.     dirEntryPtr = (Fslcl_DirEntry *)cacheBlockPtr->blockAddr;
  2162.     while (blockOffset < length) {
  2163.         if (dirEntryPtr->fileNumber != 0) {
  2164.         /*
  2165.          * A valid directory record.
  2166.          */
  2167.         if ((strcmp(".", dirEntryPtr->fileName) == 0) ||
  2168.             (strcmp("..", dirEntryPtr->fileName) == 0)) {
  2169.             /*
  2170.              * "." and ".." are ok
  2171.              */
  2172.         } else {
  2173.             Fscache_UnlockBlock(cacheBlockPtr, (time_t) 0,
  2174.                             -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  2175.             return(FALSE);
  2176.         }
  2177.         }
  2178.         blockOffset += dirEntryPtr->recordLength;
  2179.         dirEntryPtr = 
  2180.         (Fslcl_DirEntry *)((int)dirEntryPtr + dirEntryPtr->recordLength);
  2181.     }
  2182.     dirBlockNum++;
  2183.     Fscache_UnlockBlock(cacheBlockPtr, (time_t) 0,
  2184.                         -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  2185.     } while(TRUE);
  2186.     /*NOTREACHED*/
  2187. }
  2188.  
  2189. /*
  2190.  *----------------------------------------------------------------------
  2191.  *
  2192.  * CheckPermissions --
  2193.  *
  2194.  *    Check permissions on a file during lookup.  This just looks
  2195.  *    at the uid, groupIDs, and the permission bits on the file.
  2196.  *    
  2197.  *    Some semantic checking is done:
  2198.  *        type indicates what kind of file to accept.
  2199.  *        Execution of files with no execute bit is prevented for uid = 0
  2200.  *        Execution of directories is prevented.
  2201.  *    Some semantic checking is not done:
  2202.  *        Doesn't check against writing to directories.  This is
  2203.  *        done later in the FileSrvOpen routine.
  2204.  *
  2205.  * Results:
  2206.  *    FS_NO_ACCESS if the useFlags include a permission that does
  2207.  *    not fit with the uid/groupIDs of the file.
  2208.  *
  2209.  * Side effects:
  2210.  *    None.
  2211.  *
  2212.  *----------------------------------------------------------------------
  2213.  */
  2214. static ReturnStatus
  2215. CheckPermissions(handlePtr, useFlags, idPtr, type)
  2216.     Fsio_FileIOHandle        *handlePtr;
  2217.     register int        useFlags;
  2218.     register Fs_UserIDs        *idPtr;
  2219.     int             type;
  2220. {
  2221.     register Fsdm_FileDescriptor    *descPtr;
  2222.     register int        *groupPtr;
  2223.     register unsigned int     permBits;
  2224.     register int         index;
  2225.     register int        uid = idPtr->user;
  2226.     ReturnStatus         status;
  2227.  
  2228.     if (handlePtr->hdr.fileID.type != FSIO_LCL_FILE_STREAM) {
  2229.     panic( "CheckPermissions on non-local file\n");
  2230.     return(FAILURE);
  2231.     }
  2232.     descPtr = handlePtr->descPtr;
  2233.     /*
  2234.      * Make sure the file type matches.  FS_FILE means any type, otherwise
  2235.      * it should match exactly.
  2236.      */
  2237.     if (type != FS_FILE && type != descPtr->fileType) {
  2238.     /*
  2239.      * Patch around the fact that FS_REMOTE_LINK and FS_SYMBOLIC_LINK
  2240.      * get or'ed together, but they are not-proper bit fields.
  2241.      * (They equal 3 and 2, respectively.)
  2242.      * Hence we allow a regular symbolic link to satisfy a
  2243.      * request for a remote link.
  2244.      */
  2245.     if ((type == (FS_REMOTE_LINK|FS_SYMBOLIC_LINK)) &&
  2246.         ((descPtr->fileType == FS_SYMBOLIC_LINK) ||
  2247.          (descPtr->fileType == FS_REMOTE_LINK))) {
  2248. /*        printf( "Allowing a symlink for a remote link\n");*/
  2249.     } else {
  2250.         switch(type) {
  2251.         case FS_DIRECTORY:
  2252.             return(FS_NOT_DIRECTORY);
  2253.         default:
  2254.             return(FS_WRONG_TYPE);
  2255.         }
  2256.     }
  2257.     }
  2258.     /*
  2259.      * Dis-allow execution of directories...
  2260.      */
  2261.     if ((type == FS_FILE) && (useFlags & FS_EXECUTE) &&
  2262.     (descPtr->fileType != FS_FILE)) {
  2263.     return(FS_WRONG_TYPE);
  2264.     }
  2265.     /*
  2266.      * Reset SETUID/SETGID bit when writing a file.
  2267.      */
  2268.     if ((useFlags & FS_WRITE) && (descPtr->fileType == FS_FILE) &&
  2269.     (descPtr->permissions & (FS_SET_UID|FS_SET_GID))) {
  2270.     descPtr->permissions &= ~(FS_SET_UID|FS_SET_GID);
  2271.     descPtr->flags |= FSDM_FD_PERMISSIONS_DIRTY;
  2272.     }
  2273.     /*
  2274.      * Check for ownership permission.  This probably redundant with
  2275.      * respect to the checking done by FslclSetAttr.
  2276.      */
  2277. #ifdef notdef
  2278.     if (useFlags & FS_OWNERSHIP) {
  2279.     if ((uid != descPtr->uid) && (uid != 0)) {
  2280.         return(FS_NOT_OWNER);
  2281.     }
  2282.     }
  2283. #endif notdef
  2284.     /*
  2285.      * Check read/write/exec permissions against one of the owner bits,
  2286.      * the group bits, or the world bits.  'permBits' is set to
  2287.      * be the corresponding bits from the file descriptor and then
  2288.      * shifted over so the comparisions are against the WORLD bits.
  2289.      */
  2290.     if (uid == 0) {
  2291.     /*
  2292.      * For normal files, only check for execute permission.  This
  2293.      * prevents root from being able to execute ordinary files by
  2294.      * accident.  However, root has complete access to directories.
  2295.      */
  2296.     if (descPtr->fileType == FS_DIRECTORY) {
  2297.         return(SUCCESS);
  2298.     }
  2299.     useFlags &= FS_EXECUTE;
  2300.     }
  2301.     if (uid == descPtr->uid) {
  2302.     permBits = (descPtr->permissions >> 6) & 07;
  2303.     } else {
  2304.     for (index = idPtr->numGroupIDs, groupPtr = idPtr->group;
  2305.          index > 0;
  2306.          index--, groupPtr++) {
  2307.         if (*groupPtr == descPtr->gid) {
  2308.         permBits = (descPtr->permissions >> 3) & 07;
  2309.         goto havePermBits;
  2310.         }
  2311.     }
  2312.     permBits = descPtr->permissions & 07;
  2313.     }
  2314. havePermBits:
  2315.     if (((useFlags & FS_READ) && ((permBits & FS_WORLD_READ) == 0)) ||
  2316.     ((useFlags & FS_WRITE) && ((permBits & FS_WORLD_WRITE) == 0)) ||
  2317.     ((useFlags & FS_EXECUTE) && ((permBits & FS_WORLD_EXEC) == 0))) {
  2318.     /*
  2319.      * The file's permission don't include what is needed.
  2320.      */
  2321.     status = FS_NO_ACCESS;
  2322.     } else {
  2323.     status = SUCCESS;
  2324.     }
  2325.     return(status);
  2326. }
  2327.  
  2328.  
  2329. /*
  2330.  *----------------------------------------------------------------------
  2331.  *
  2332.  * CacheDirBlockWrite --
  2333.  *
  2334.  *    Write into a cache block returned from Fscache_BlockRead.  Used only
  2335.  *    for writing directories.
  2336.  *
  2337.  * Results:
  2338.  *    SUCCESS unless error when allocating disk space.
  2339.  *
  2340.  * Side effects:
  2341.  *    The cache block is unlocked.  It is deleted if the offset is the
  2342.  *    beginning of the block and the disk allocation failed.
  2343.  *
  2344.  *----------------------------------------------------------------------
  2345.  */
  2346.  
  2347. static ReturnStatus
  2348. CacheDirBlockWrite(handlePtr, blockPtr, blockNum, length)
  2349.     register    Fsio_FileIOHandle    *handlePtr;    /* Handle for file. */
  2350.     register    Fscache_Block    *blockPtr;    /* Cache block. */
  2351.     int                blockNum;    /* Block number. */
  2352.     int                length;        /* Number of valid bytes in
  2353.                          * the block. */
  2354. {
  2355.     ReturnStatus    status = SUCCESS;
  2356.     int            blockAddr = FSDM_NIL_INDEX;
  2357.     Boolean        newBlock;
  2358.     int            flags = FSCACHE_CLEAR_READ_AHEAD;
  2359.     int            offset;
  2360.     int            newLastByte;
  2361.     int            blockSize;
  2362.  
  2363.     offset =  blockNum * FS_BLOCK_SIZE;
  2364.     newLastByte = offset + length - 1;
  2365.     (void) (handlePtr->cacheInfo.backendPtr->ioProcs.allocate)
  2366.     ((Fs_HandleHeader *)handlePtr, offset, length, 0,
  2367.         &blockAddr, &newBlock);
  2368. #ifdef lint
  2369.     (void) Fsdm_BlockAllocate((Fs_HandleHeader *)handlePtr, offset, length,
  2370.             0, &blockAddr, &newBlock);
  2371.     (void) FsrmtFileBlockAllocate((Fs_HandleHeader *)handlePtr, offset, length,
  2372.             0, &blockAddr, &newBlock);
  2373. #endif /* lint */
  2374.     if (blockAddr == FSDM_NIL_INDEX) {
  2375.     status = FS_NO_DISK_SPACE;
  2376.     printf("CacheDirBlockWrite: out of space for %s.\n",
  2377.            Fsutil_HandleName(handlePtr));    /* DEBUG */
  2378.     if (handlePtr->descPtr->lastByte + 1 < offset) {
  2379.         /*
  2380.          * Delete the block if are appending and this was a new cache
  2381.          * block.
  2382.          */
  2383.         flags = FSCACHE_DELETE_BLOCK;
  2384.     }
  2385.     }
  2386.     Fscache_UpdateDirSize(&handlePtr->cacheInfo, newLastByte);
  2387.     handlePtr->descPtr->dataModifyTime = Fsutil_TimeInSeconds();
  2388.     handlePtr->descPtr->descModifyTime = handlePtr->descPtr->dataModifyTime;
  2389.     handlePtr->descPtr->flags |= FSDM_FD_MODTIME_DIRTY;
  2390.     fs_Stats.blockCache.dirBytesWritten += FSLCL_DIR_BLOCK_SIZE;
  2391.     fs_Stats.blockCache.dirBlockWrites++;
  2392.     blockSize = handlePtr->descPtr->lastByte + 1 - (blockNum * FS_BLOCK_SIZE);
  2393.     if (blockSize > FS_BLOCK_SIZE) {
  2394.     blockSize = FS_BLOCK_SIZE;
  2395.     }
  2396.     Fscache_UnlockBlock(blockPtr, (time_t) Fsutil_TimeInSeconds(), blockAddr,
  2397.             blockSize, flags);
  2398.     return(status);
  2399. }
  2400.  
  2401.  
  2402. /*
  2403.  *----------------------------------------------------------------------
  2404.  *
  2405.  * Fslcl_CheckDirLog --
  2406.  *
  2407.  *    Check the directory op log against the contents of a dir.  If there's
  2408.  *    a discrepancy, modify the directory to contain the correct files
  2409.  *    and directories.
  2410.  *
  2411.  * Results:
  2412.  *    None.
  2413.  *
  2414.  * Side effects:
  2415.  *    Modify the directory to contain the correct files.
  2416.  *
  2417.  *----------------------------------------------------------------------
  2418.  */
  2419. void
  2420. Fslcl_CheckDirLog(parentHandlePtr, dirLogList)
  2421.     Fsio_FileIOHandle    *parentHandlePtr;
  2422.     List_Links        *dirLogList;
  2423. {
  2424.     List_Links        *itemPtr;
  2425.     char        *component;
  2426.     int            compLen;
  2427.     FslclHashEntry    *entryPtr;    /* Name cache entry */
  2428.     Fsio_FileIOHandle    *handlePtr;
  2429.     Boolean        found;
  2430.     int            dirBlockNum;
  2431.     ReturnStatus    status;
  2432.     Fscache_Block    *cacheBlockPtr;    /* Cache block */
  2433.     int            length;
  2434.     int            blockOffset;
  2435.     Fslcl_DirEntry    *dirEntryPtr;    /* Reference to directory entry */
  2436.     char        buf[256];
  2437.  
  2438.  
  2439.     if (!recov_Transparent) {
  2440.     panic("Fslcl_CheckDirLog: shouldn't have been called.\n");
  2441.     }
  2442.     LIST_FORALL(dirLogList, itemPtr) {
  2443.     /* Try cached lookup first. */
  2444.  
  2445.     found = FALSE;
  2446.     Fsrecov_GetComponent(itemPtr, &component, &compLen);
  2447.     strncpy(buf, component, compLen);
  2448.     buf[compLen] = '\0';
  2449.     entryPtr =
  2450.         FSLCL_HASH_LOOK_ONLY(fslclNameTablePtr, component, parentHandlePtr);
  2451.  
  2452.     if (entryPtr != (FslclHashEntry *)NIL) {
  2453.         if (entryPtr->hdrPtr->fileID.type != FSIO_LCL_FILE_STREAM) {
  2454.         panic("Fslcl_CheckDirLog: got trashy handle from cache");
  2455.         }
  2456.         handlePtr = (Fsio_FileIOHandle *) entryPtr->hdrPtr;
  2457.         found = TRUE;
  2458.     } else {
  2459.         dirBlockNum = 0;
  2460.         do {
  2461.         status = Fscache_BlockRead(&parentHandlePtr->cacheInfo,
  2462.             dirBlockNum, &cacheBlockPtr, &length, FSCACHE_DIR_BLOCK,
  2463.             FALSE);
  2464.         if (status != SUCCESS || length == 0) {
  2465.             break;
  2466.         }
  2467.         dirEntryPtr = (Fslcl_DirEntry *)cacheBlockPtr->blockAddr;
  2468.         blockOffset = 0;
  2469.         while (blockOffset < length) {
  2470.             if (dirEntryPtr->recordLength <= 0) {
  2471.             printf(" File ID <%d, %d, %d>",
  2472.                      parentHandlePtr->hdr.fileID.serverID,
  2473.                      parentHandlePtr->hdr.fileID.major,
  2474.                      parentHandlePtr->hdr.fileID.minor);
  2475.             printf(" dirBlockNum <%d>, blockOffset <%d>",
  2476.                      dirBlockNum, blockOffset);
  2477.             printf("\n");
  2478.                 Fscache_UnlockBlock(cacheBlockPtr, (time_t) 0,
  2479.                         -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  2480.             panic("Fslcl_CheckDirLog: Corrupted directory?");
  2481.             }
  2482.  
  2483.             if (dirEntryPtr->fileNumber != 0) {
  2484.             /*
  2485.              * A valid directory record.  If component and the directory
  2486.              * entry are the same length then compare them for a match.
  2487.              * This String Compare is in-lined for efficiency.
  2488.              */
  2489.             if ((dirEntryPtr->nameLength == compLen)) {
  2490.                 if (strncmp(component, dirEntryPtr->fileName,
  2491.                     compLen) == 0) {
  2492.                 found = TRUE;
  2493.                 break;
  2494.                 }
  2495.             }
  2496.             } else {
  2497.             printf("Uh oh, dirEntryPtr->fileNumber is 0\n");
  2498.             }
  2499.             blockOffset += dirEntryPtr->recordLength;
  2500.             dirEntryPtr = (Fslcl_DirEntry *)((int)dirEntryPtr +
  2501.                          dirEntryPtr->recordLength);
  2502.         }
  2503.         dirBlockNum++;
  2504.         Fscache_UnlockBlock(cacheBlockPtr, (time_t) 0, -1, 0, 0);
  2505.         } while(!found);
  2506.     }
  2507.     /* It's been found or not.  Now deal with the result. */
  2508.     if (found) {
  2509.         printf("Found %s\n", component);
  2510.     } else {
  2511.         printf("Didn't find %s\n", component);
  2512.     }
  2513.     }
  2514.     return;
  2515. }
  2516.